diff --git a/scripts/util/conv_rates_immersed.lua b/scripts/util/conv_rates_immersed.lua new file mode 100644 index 000000000..5b077f9e8 --- /dev/null +++ b/scripts/util/conv_rates_immersed.lua @@ -0,0 +1,740 @@ +util = util or {} +util.rates = util.rates or {} +util.rates.static = util.rates.static or {} + +ug_load_script("util/persistence.lua") + +-------------------------------------------------------------------------------- +-- Std Functions (used as defaults) +-------------------------------------------------------------------------------- + +function util.rates.static.StdPrepareInitialGuess(u, lev, minLev, maxLev, + domainDisc, solver) + + if lev > minLev then + Prolongate(u[lev], u[lev-1]); + write(">> Solution interpolated as start value from coarser level.\n") + else + u[lev]:set(0.0) + write(">> Solution set to zero on coarsest level.\n") + end +end + + +function util.rates.static.StdComputeLinearSolution(u, domainDisc, solver) + + -- create operator from discretization + local A = AssembledLinearOperator(domainDisc) + local b = u:clone() + write(">> Algebra created.\n") + + -- 1. init operator + domainDisc:assemble_linear(A, b) + write(">> Matrix and Rhs assembled.\n") + + -- 2. set dirichlet values in start iterate + domainDisc:adjust_solution(u) + write(">> Inital guess for solution prepared.\n") + + -- 3. init solver for linear Operator + solver:init(A, u) + write(">> Linear Solver initialized.\n") + + -- 4. apply solver + if solver:apply_return_defect(u, b) ~= true then + write(">> Linear solver failed. Aborting."); exit(); + end +end + +function util.rates.static.StdComputeNonLinearSolution(u, domainDisc, solver) + + solver:init(AssembledOperator(domainDisc, u:grid_level())) + if solver:apply(u) == false then + print (">> Newton solver apply failed."); exit(); + end + write(">> Newton Solver done.\n") +end + +function util.rates.static.StdMaxLevelPadding(p) + return math.floor(p/2) +end + +function util.rates.static.StdMinLevelPadding(p) + return 0 +end + + +function util.rates.static.NoMaxLevelPadding(p) + return 0 +end + +function util.rates.static.NoMinLevelPadding(p) + return 0 +end + +-------------------------------------------------------------------------------- +-- Label names +-------------------------------------------------------------------------------- + +util.rates.static.StdLabel = util.rates.static.StdLabel or {} + +function util.rates.static.StdLabel.MeasLatexP(disc, p) + return disc.." $\\mathbb{P}_{"..p.."}$" +end + +function util.rates.static.StdLabel.MeasLatexQ(disc, p) + return disc.." $\\mathbb{Q}_{"..p.."}$" +end + +function util.rates.static.StdLabel.XLatex(x) + local gpXLabel ={ DoFs = "Anzahl Unbekannte", h = "h (Gitterweite)"} + return gpXLabel[x] +end + +function util.rates.static.StdLabel.YLatex(f, t, n) + local gpType = { ["l-exact"] = "{}", + ["l-lmax"] = "h_{\\text{min}}", + ["l-prev"] = "{h/2}", + } + local gpNorm = { l2 = "L_2", h1 = "H^1"} + + if t == "interpol" then + return "$\\norm{\\mathcal{I}_h("..f..") - "..f.."}_{"..gpNorm[n].."}$" + else + return "$\\norm{"..f.."_h - "..f.."_{"..gpType[t].."} }_{ "..gpNorm[n].."}$" + end +end + +function util.rates.static.StdLabel.MeasPdfP(disc, p) + return disc.." $P_"..p.."$" +end + +function util.rates.static.StdLabel.MeasPdfQ(disc, p) + return disc.." $Q_"..p.."$" +end + +function util.rates.static.StdLabel.XPdf(x) + local gpXLabel ={ DoFs = "Anzahl Unbekannte", h = "h (Gitterweite)"} + return gpXLabel[x] +end + +function util.rates.static.StdLabel.YPdf(f, t, n) + local gpType = { ["l-exact"] = "{}", + ["l-lmax"] = "h_{\\text{min}}", + ["l-prev"] = "{h/2}", + } + local gpNorm = { l2 = "L_2", h1 = "H^1"} + + if t == "interpol" then + return "$|| I_h("..f..") - "..f.." ||_{"..gpNorm[n].."}$" + else + return "$|| "..f.."_h - "..f.."_{"..gpType[t].."} ||_{"..gpNorm[n].."}$" + end +end + +-------------------------------------------------------------------------------- +-- util.rates.static.compute (main-function) +-------------------------------------------------------------------------------- + +--[[! +Computes convergence rates for a static problem + +In the convergence rate setup the following parameters can be passed: +- (required) CreateDomain() + function used to create Domain +- (required) CreateApproxSpace(dom, discType, p) + function used to create ApproximationSpace +- (required) CreateDomainDisc(approxSpace, discType, p) + function used to create Domain Discretization +- (required) CreateSolver(approxSpace, discType, p) + function used to create Solver +- (required) DiscTypes + Array containing types, orders and level to be looped +- (optional) ComputeSolution(u, domainDisc, solver) + function used to compute solution +- (optional) PrepareInitialGuess + function used to prepare Initial Guess +- (optional) ExactSol + Array containing exact solution as a function +- (optional) ExactGrad + Array containing exact gradients as a function + +@param ConvRate Setup setup used +]]-- +function util.rates.static.compute(ConvRateSetup) + + -- check passed param + local CRS + if ConvRateSetup == nil then print("No setup passed."); exit() + else CRS = ConvRateSetup end + + -- create directories + local plotPath = CRS.plotPath or "plots/" + local solPath = CRS.solPath or "sol/" + local dataPath = CRS.dataPath or "data/" + + local gpOptions = CRS.gpOptions or + { + grid = true, + logscale = true, + mtics = true + } + + -- check for methods + local PrepareInitialGuess = CRS.PrepareInitialGuess or util.rates.static.StdPrepareInitialGuess + local ComputeSolution = CRS.ComputeSolution or util.rates.static.StdComputeNonLinearSolution + local CreateApproxSpace = CRS.CreateApproxSpace + local CreateDomainDisc = CRS.CreateDomainDisc + local CreateSolver = CRS.CreateSolver + local CreateDomain = CRS.CreateDomain + local MaxLevelPadding = CRS.MaxLevelPadding or util.rates.static.StdMaxLevelPadding + local MinLevelPadding = CRS.MinLevelPadding or util.rates.static.StdMinLevelPadding + + if CreateApproxSpace == nil or CreateDomainDisc == nil or + CreateSolver == nil or CreateDomain == nil then + print("You must pass: CreateApproxSpace, CreateDomainDisc, CreateSolver, CreateDomain") + exit() + end + + local DiscTypes = CRS.DiscTypes + + local maxlevel = CRS.maxlevel; if maxlevel == nil then maxlevel = true end + local prevlevel = CRS.prevlevel; if prevlevel == nil then prevlevel = true end + local exact = CRS.exact; if exact == nil then exact = true end + local interpol = CRS.interpol; if interpol == nil then interpol = true end + local plotSol = CRS.plotSol; if plotSol == nil then plotSol = false end + + local ExactSol = CRS.ExactSol + local ExactGrad = CRS.ExactGrad + local PlotCmps = CRS.PlotCmps + + local MeasLabel = CRS.MeasLabel or util.rates.static.StdLabel.MeasLatexP + local XLabel = CRS.XLabel or util.rates.static.StdLabel.XLatex + local YLabel = CRS.YLabel or util.rates.static.StdLabel.YLatex + + -------------------------------------------------------------------- + -- Loop Discs + -------------------------------------------------------------------- + + local function ensureDir(name) + if not(DirectoryExists(name)) then CreateDirectory(name) end + end + + if plotSol then ensureDir(solPath) end + + -- compute element size + local dom = CreateDomain() + local numRefs = dom:grid():num_levels() - 1; + + -- to store measurement + local gpData = {}; + local errors = {}; + + for _, DiscType in ipairs(DiscTypes) do + + local disc = DiscType.type + if disc == nil then print("type required."); exit(); end + + local pmin = DiscType.pmin or 1 + local pmax = DiscType.pmax or 1 + local lmin = DiscType.lmin or 0 + local lmax = DiscType.lmax or numRefs + + if lmin > lmax then print("lmin: "..lmin.." must be less or equal lmax: "..lmax); exit(); end + if lmax > numRefs then print("lmax: "..lmax.." must be less or equal numRefs: "..numRefs); exit(); end + + errors[disc] = errors[disc] or {} + + for p = pmin, pmax do + + errors[disc][p] = errors[disc][p] or {} + + local maxLev = lmax - MaxLevelPadding(p) + local minLev = lmin + MinLevelPadding(p) + + -------------------------------------------------------------------- + -- Print Setup + -------------------------------------------------------------------- + + print("\n") + print(">> -------------------------------------------------------------------") + print(">> Computing solutions and error norms of the following problem") + print(">> -------------------------------------------------------------------") + print(">> dim = " .. dim) + print(">> grid = " .. gridName) + print(">> minLev = " .. minLev) + print(">> maxLev = " .. maxLev) + print(">> type = " .. disc) + print(">> order = " .. p) + print("\n") + + -------------------------------------------------------------------- + -- Create ApproxSpace, Disc and Solver + -------------------------------------------------------------------- + + print(">> Create ApproximationSpace: "..disc..", "..p) + local approxSpace = CreateApproxSpace(dom, disc, p) + + print(">> Create Domain Disc: "..disc..", "..p) + local domainDisc = CreateDomainDisc(approxSpace, disc, p) + + --local solver = CreateSolver(approxSpace, disc, p) + + -- get names in approx space + local SpaceCmp = approxSpace:names() + + -- per default compute each Space-cmp + if PlotCmps == nil then + PlotCmps = {} + for f = 1,#SpaceCmp do + PlotCmps[SpaceCmp[f]] = {SpaceCmp[f]} + end + end + + -- check functions to measure + for _,Cmps in pairs(PlotCmps) do + for _, cmp in pairs(Cmps) do + if not table.contains(SpaceCmp, cmp) then + print("Cmp: '"..cmp.."' not contained in ApproxSpace."); + exit() + end + end + end + + -------------------------------------------------------------------- + -- Create Solutions on each level + -------------------------------------------------------------------- + + write(">> Allocating storage for solution vectors.\n") + local u = {} + for lev = minLev, maxLev do + u[lev] = GridFunction(approxSpace, lev) + end + + -------------------------------------------------------------------- + -- Compute Solution on each level + -------------------------------------------------------------------- + if exact or maxlevel or prevlevel then + for lev = minLev, maxLev do + print(">> Create Solver on lev "..lev) + + local solver = CreateSolver(approxSpace, disc, p, lev) + + write("\n>> Computing Level "..lev..", "..disc..", "..p..".\n") + + write(">> Preparing inital guess on level "..lev..".\n") + --solver = CreateSolver(approxSpace, disc, p) + PrepareInitialGuess(u, lev, minLev, maxLev, domainDisc, solver, approxSpace, disc, p) + + write(">> Start: Computing solution on level "..lev..".\n") + --solver = CreateSolver(approxSpace, disc, p) + ComputeSolution(u[lev], domainDisc, solver) + write(">> End: Solver done.\n") + + if plotSol then + WriteGridFunctionToVTK(u[lev], solPath.."sol_"..disc..p.."_l"..lev) + write(">> Solution written to: "..solPath.."sol_"..disc..p.."_l"..lev.."\n"); + end + + solver = nil + end + end + + approxSpace, domainDisc = nil, nil + collectgarbage() + + -------------------------------------------------------------------- + -- Compute Error Norms on each level + -------------------------------------------------------------------- + + -- prepare error measurement + local err = errors[disc][p] + err.h, err.DoFs, err.level = {}, {}, {} + for lev = minLev, maxLev do + err.h[lev] = MaxElementDiameter(dom, lev) + err.level[lev] = lev + err.DoFs[lev] = u[lev]:num_dofs() + end + + -- loop levels and compute error + for lev = maxLev, minLev, -1 do + write("\n>> Error Norm values on Level "..lev..".\n") + + local quadOrder = p*p+3 + write(">> #DoF on Level "..lev.." is "..err.DoFs[lev] .."\n"); + + -- compute for each component + for f, Cmps in pairs(PlotCmps) do + + -- create component + err[f] = err[f] or {} + + -- help fct to create an measurement + local function createMeas(f, t, n) + err[f][t] = err[f][t] or {} + err[f][t][n] = err[f][t][n] or {} + err[f][t][n].value = err[f][t][n].value or {} + return err[f][t][n].value + end + + -- check for exact solution and grad + local solAvail, gradAvail = true, true + for _,cmp in pairs(Cmps) do + if ExactSol == nil or ExactSol[cmp] == nil then solAvail = false end + if ExactGrad == nil or ExactGrad[cmp] == nil then gradAvail = false end + end + + -- w.r.t exact solution + if exact and solAvail then + local value = createMeas(f, "l-exact", "l2") + value[lev] = 0.0 + for _,cmp in pairs(Cmps) do + value[lev] = value[lev] + math.pow(L2Error(ExactSol[cmp], u[lev], cmp, 0.0, quadOrder), 2) + end + value[lev] = math.sqrt(value[lev]) + write(">> L2 l-exact for "..f.." on Level "..lev.." is "..string.format("%.3e", value[lev]) .."\n"); + + if gradAvail then + local value = createMeas(f, "l-exact", "h1") + value[lev] = 0.0 + for _,cmp in pairs(Cmps) do + value[lev] = value[lev] + math.pow(H1Error(ExactSol[cmp], ExactGrad[cmp], u[lev], cmp, 0.0, quadOrder), 2) + end + value[lev] = math.sqrt(value[lev]) + write(">> H1 l-exact for "..f.." on Level "..lev.." is "..string.format("%.3e", value[lev]) .."\n"); + end + end + + if interpol and solAvail then + local uExact = u[lev]:clone() + for _,cmp in pairs(Cmps) do + Interpolate(ExactSol[cmp], uExact, cmp) + end + + local value = createMeas(f, "interpol", "l2") + value[lev] = 0.0 + for _,cmp in pairs(Cmps) do + value[lev] = value[lev] + math.pow(L2Error(ExactSol[cmp], uExact, cmp, 0.0, quadOrder), 2) + end + value[lev] = math.sqrt(value[lev]) + write(">> L2 interpol for "..f.." on Level "..lev.." is "..string.format("%.3e", value[lev]) .."\n"); + + if gradAvail then + local value = createMeas(f, "interpol", "h1") + value[lev] = 0.0 + for _,cmp in pairs(Cmps) do + value[lev] = value[lev] + math.pow(H1Error(ExactSol[cmp], ExactGrad[cmp], uExact, cmp, 0.0, quadOrder), 2) + end + value[lev] = math.sqrt(value[lev]) + write(">> H1 interpol for "..f.." on Level "..lev.." is "..string.format("%.3e", value[lev]) .."\n"); + end + + uExact = nil + end + + + -- w.r.t max level solution + if maxlevel and lev < maxLev then + local value = createMeas(f, "l-lmax", "l2") + value[lev] = 0.0 + for _,cmp in pairs(Cmps) do + value[lev] = value[lev] + math.pow(L2ErrorInside(u[maxLev], cmp, u[lev], cmp, quadOrder), 2) + -- value[lev] = value[lev] + math.pow(L2Error(u[maxLev], cmp, u[lev], cmp, quadOrder), 2) + end + value[lev] = math.sqrt(value[lev]) + write(">> L2 l-lmax for "..f.." on Level "..lev.." is "..string.format("%.3e", value[lev]) .."\n"); + + local value = createMeas(f, "l-lmax", "h1") + value[lev] = 0.0 + for _,cmp in pairs(Cmps) do + value[lev] = value[lev] + math.pow(H1Error(u[maxLev], cmp, u[lev], cmp, quadOrder), 2) + end + value[lev] = math.sqrt(value[lev]) + write(">> H1 l-lmax for "..f.." on Level "..lev.." is "..string.format("%.3e", value[lev]) .."\n"); + end + + + -- w.r.t previous level solution + if prevlevel and lev < maxLev then + local value = createMeas(f, "l-prev", "l2") + value[lev] = 0.0 + for _,cmp in pairs(Cmps) do + value[lev] = value[lev] + math.pow(L2ErrorInside(u[lev+1], cmp, u[lev], cmp, quadOrder), 2) + -- value[lev] = value[lev] + math.pow(L2Error(u[lev+1], cmp, u[lev], cmp, quadOrder), 2) + end + value[lev] = math.sqrt(value[lev]) + write(">> L2 l-(l-1) for "..f.." on Level "..lev.." is "..string.format("%.3e", value[lev]) .."\n"); + + local value = createMeas(f, "l-prev", "h1") + value[lev] = 0.0 + for _,cmp in pairs(Cmps) do + value[lev] = value[lev] + math.pow(H1Error(u[lev+1], cmp, u[lev], cmp, quadOrder), 2) + end + value[lev] = math.sqrt(value[lev]) + write(">> H1 l-(l-1) for "..f.." on Level "..lev.." is "..string.format("%.3e", value[lev]) .."\n"); + end + end -- end fct + + end -- end level + + for lev = minLev, maxLev do u[lev] = nil end + u = nil + collectgarbage() + + -------------------------------------------------------------------- + -- Compute Factors and Rates + -------------------------------------------------------------------- + + for f, _ in pairs(PlotCmps) do + for t, _ in pairs(err[f]) do + for n, _ in pairs(err[f][t]) do + + local meas = err[f][t][n] + + meas.fac = meas.fac or {} + meas.rate = meas.rate or {} + + local value = meas.value + local fac = meas.fac + local rate = meas.rate + + for lev, _ in pairs(value) do + if value[lev] ~= nil and value[lev-1] ~= nil then + fac[lev] = value[lev-1]/value[lev] + rate[lev] = math.log(fac[lev]) / math.log(2) + end + end + + end + end + end + + -------------------------------------------------------------------- + -- Write Data to Screen + -------------------------------------------------------------------- + + for f, Cmps in pairs(PlotCmps) do + + write("\n>> Statistic for type: "..disc..", order: "..p..", comp: "..f.." [ ") + for _, cmp in pairs(Cmps) do write(cmp.." ") end + print("]\n") + + local values = {err.level, err.h, err.DoFs} + local heading = {"L", "h", "#DoFs"} + local format = {"%d", "%.2e", "%d"} + + for t, _ in pairs(err[f]) do + for n, _ in pairs(err[f][t]) do + local meas = err[f][t][n] + table.append(values, {meas.value, meas.rate}) + table.append(heading,{n.." "..t, "rate"}) + table.append(format, {"%.2e", "%.3f"}) + end + end + + table.print(values, {heading = heading, format = format, + hline = true, vline = true, forNil = "--"}) + end + + end -- end loop over p + end -- end loop over type + + + -------------------------------------------------------------------- + -- Write gnuplot data + -------------------------------------------------------------------- + + -- the following is serial and one proc doing it is sufficient + if ProcRank() ~= 0 then return end + ensureDir(dataPath) + ensureDir(plotPath) + + -- help fct to create a plot + local plots = {} + local function accessPlot(...) + local keys = arg + local plot = plots + for _, key in ipairs(keys) do + plot[key] = plot[key] or {} + plot = plot[key] + end + return plot + end + + local function getPlot(...) + local plot = accessPlot(...) + local pl = table.ideepcopy( plot ) + pl.label = plot.label + return pl + end + + for disc, _ in pairs(errors) do + for p, _ in pairs(errors[disc]) do + for f, _ in pairs(PlotCmps) do + for t, _ in pairs(errors[disc][p][f]) do + for n, _ in pairs(errors[disc][p][f][t]) do + + -- write l2 and h1 to data file + local file = dataPath..table.concat({"error",disc,p,f,t,n},"_")..".dat" + local cols = {errors[disc][p].DoFs, errors[disc][p].h, errors[disc][p][f][t][n].value} + gnuplot.write_data(file, cols) + + -- store dataset + for xCol, x in ipairs({"DoFs", "h"}) do + local dataset = {label=MeasLabel(disc, p), file=file, style="linespoints", xCol, 3} + local label = { x = XLabel(x), y = YLabel(f,t,n)} + + local function addSet(plot, dataset, label) + table.insert( plot, dataset) + plot.label = label + end + + addSet( accessPlot(disc, p, f, t, n, x), dataset, label) + addSet( accessPlot(disc, f, t, n, x), dataset, label) + addSet( accessPlot("all", f, t, n, x), dataset, label) + end + + end + end + end + end + end + + -------------------------------------------------------------------- + -- Execute Plot of gnuplot + -------------------------------------------------------------------- + + -- one plot + local validP + ensureDir(plotPath.."dataset/") + ensureDir(plotPath.."disc/") + ensureDir(plotPath.."multi/") + for disc, _ in pairs(errors) do + for p, _ in pairs(errors[disc]) do + for f, _ in pairs(PlotCmps) do + for t, _ in pairs(errors[disc][p][f]) do + for n, _ in pairs(errors[disc][p][f][t]) do + for _, x in ipairs({"DoFs", "h"}) do + + -- single dataset + local file = plotPath.."dataset/"..table.concat({disc,p,f,t,n,x},"_") + gpData[file] = getPlot(disc, p, f, t, n, x) + + -- grouping by (disc+p) + local file = plotPath.."disc/"..table.concat({f,disc,t,n,x}, "_") + gpData[file] = getPlot(disc, f, t, n, x) + + -- grouping (all discs+p) + local file = plotPath.."disc/"..table.concat({f,"all",t,n,x}, "_") + gpData[file] = getPlot("all", f, t, n, x) + + + validP = p + end + end + end + end + end + end + + for disc, _ in pairs(errors) do + local p = validP + for f, _ in pairs(PlotCmps) do + for t, _ in pairs(errors[disc][p][f]) do + for n, _ in pairs(errors[disc][p][f][t]) do + for _, x in ipairs({"DoFs", "h"}) do + + -- multi-plot: all discs for one norm + local file = plotPath.."multi/"..table.concat({f,t,n,x}, "_") + gpData[file] = gpData[file] or {} + gpData[file].multiplot = {rows = 1} + table.insert( gpData[file], getPlot(disc, f, t, n, x) ) + + -- multi-plot: all norms for one disc + local file = plotPath.."multi/"..table.concat({f,disc,t,x}, "_") + gpData[file] = gpData[file] or {} + gpData[file].multiplot = {cols = 1} + table.insert( gpData[file], getPlot(disc, f, t, n, x) ) + + -- multi-plot: all types for one disc and one norm + local file = plotPath.."multi/"..table.concat({f,disc,n,x}, "_") + gpData[file] = gpData[file] or {} + gpData[file].multiplot = {cols = 1} + table.insert( gpData[file], getPlot(disc, f, t, n, x) ) + + -- multi-plot: all comps for one disc and one norm + local file = plotPath.."multi/"..table.concat({"all",disc,t,n,x}, "_") + gpData[file] = gpData[file] or {} + gpData[file].multiplot = {cols = 1} + table.insert( gpData[file], getPlot(disc, f, t, n, x) ) + + end + end + end + end + end + + -- multi-plot: all discs for all norm + for _, n in pairs({"h1", "l2"}) do + for disc, _ in pairs(errors) do + local p = validP + for f, _ in pairs(PlotCmps) do + for t, _ in pairs(errors[disc][p][f]) do + if errors[disc][p][f][t][n] then + for _, x in ipairs({"DoFs", "h"}) do + + local file = plotPath.."multi/"..table.concat({f,t,x}, "_") + gpData[file] = gpData[file] or {} + gpData[file].multiplot = {cols = 2} + table.insert( gpData[file], getPlot(disc, f, t, n, x) ) + + end + end + end + end + end + end + + -- save for reuse + persistence.store(dataPath.."gp-data-files.lua", gpData); + + -- create scheduled plots + if CRS.noplot == nil or CRS.noplot == false then + for plotFile, data in pairs(gpData) do + local opt = table.deepcopy(gpOptions) + if data.multiplot then opt.multiplot = data.multiplot end + gnuplot.plot(plotFile..".tex", data, opt) + gnuplot.plot(plotFile..".pdf", data, opt) + end + end +end + + +function util.rates.static.replot(gpOptions, file) + if ProcRank() ~= 0 then return end + + local dataPath = "data/" + local plotPath = "plots/" + + local function ensureDir(name) + if not(DirectoryExists(name)) then CreateDirectory(name) end + end + + ensureDir(dataPath) + ensureDir(plotPath) + ensureDir(plotPath.."dataset/") + ensureDir(plotPath.."disc/") + ensureDir(plotPath.."multi/") + + local file = file or dataPath.."gp-data-files.lua" + local gpData = persistence.load(file); + + -- create scheduled plots + for plotFile, data in pairs(gpData) do + local opt = table.deepcopy(gpOptions) + if data.multiplot then opt.multiplot = data.multiplot end + gnuplot.plot(plotFile..".tex", data, opt) + gnuplot.plot(plotFile..".pdf", data, opt) + end + +end \ No newline at end of file diff --git a/scripts/util/domain_disc_util.lua b/scripts/util/domain_disc_util.lua index 5aa6c4a49..b1f0a01e5 100644 --- a/scripts/util/domain_disc_util.lua +++ b/scripts/util/domain_disc_util.lua @@ -115,6 +115,7 @@ function NavierStokesInflow(spMaster) local discType = spMaster:disc_type(); if discType == "fv1" then return NavierStokesInflowFV1(spMaster) + elseif discType == "fv1_cutElem" then return NavierStokesInflowFV1_cutElem(spMaster) elseif discType == "fv" then return NavierStokesInflowFV(spMaster) elseif discType == "fvcr" then return NavierStokesInflowFVCR(spMaster) elseif discType == "fe" then return NavierStokesInflowFE(spMaster) diff --git a/ugbase/bridge/disc_bridges/integrate_bridge.cpp b/ugbase/bridge/disc_bridges/integrate_bridge.cpp index af8ad94ec..b284f6fd2 100644 --- a/ugbase/bridge/disc_bridges/integrate_bridge.cpp +++ b/ugbase/bridge/disc_bridges/integrate_bridge.cpp @@ -116,6 +116,7 @@ static void DomainAlgebra(Registry& reg, string grp) reg.add_function("L2Error",static_cast, const char*, SmartPtr, const char*, int)>(&L2Error), grp); reg.add_function("L2Error",static_cast >, SmartPtr, const char*, number, int, const char*)>(&L2Error), grp); reg.add_function("L2Error",static_cast >, SmartPtr, const char*, number, int)>(&L2Error), grp); + reg.add_function("L2ErrorInside",static_cast, const char*, SmartPtr, const char*, int)>(&L2ErrorInside), grp); #ifdef UG_FOR_LUA reg.add_function("L2Error",static_cast, const char*, number, int, const char*)>(&L2Error), grp); reg.add_function("L2Error",static_cast, const char*, number, int)>(&L2Error), grp); diff --git a/ugbase/lib_disc/CMakeLists.txt b/ugbase/lib_disc/CMakeLists.txt index 4e2a03ad2..60164d83f 100644 --- a/ugbase/lib_disc/CMakeLists.txt +++ b/ugbase/lib_disc/CMakeLists.txt @@ -93,6 +93,8 @@ set(srcDiscretization domain.cpp spatial_disc/disc_util/fe_geom.cpp spatial_disc/disc_util/fvho_geom.cpp spatial_disc/disc_util/fv1_geom.cpp + spatial_disc/disc_util/fv1FT_geom.cpp + spatial_disc/disc_util/fv1Cut_geom.cpp spatial_disc/disc_util/fvcr_geom.cpp spatial_disc/disc_util/hfv1_geom.cpp spatial_disc/disc_util/hfvcr_geom.cpp diff --git a/ugbase/lib_disc/common/geometry_util.h b/ugbase/lib_disc/common/geometry_util.h index d33299dad..3cfd3dcac 100644 --- a/ugbase/lib_disc/common/geometry_util.h +++ b/ugbase/lib_disc/common/geometry_util.h @@ -802,7 +802,7 @@ struct ElementSideRayIntersectionWrapper // find side for(sideOut = 0; sideOut < rRefElem.num(dim-1); ++sideOut) { - // get corners + // A1. get corners p0 = rRefElem.id(dim-1, sideOut, 0, 0); p1 = rRefElem.id(dim-1, sideOut, 0, 1); p2 = rRefElem.id(dim-1, sideOut, 0, 2); @@ -819,7 +819,11 @@ struct ElementSideRayIntersectionWrapper // second triangle (only if 4 corners) if(rRefElem.num(dim-1, sideOut, 0) == 3) continue; - // get corner number 4 + // B1. get corner number 4 as p2 and replace p1 by p2 + // (In case of a quadrilateral whose corners are numbered counterclockwise by (1,2,3,4), + // we decompose it into the triangle with corners (1,2,3) and the triangle (1,3,4).) + + p1 = rRefElem.id(dim-1, sideOut, 0, 2); // added in order to create disjunct triangles filling the quadrilateral completely p2 = rRefElem.id(dim-1, sideOut, 0, 3); // if match: break @@ -830,6 +834,42 @@ struct ElementSideRayIntersectionWrapper if(bPositiv && t >= 0.0) break; else if(!bPositiv && t <= 0.0) break; } + + // repeat the procedures A. and B. but by cutting the quadrilateral + // along the other diagonal into 2 triangles + // (necessary for cases, where the 4 corners do not form a flat + // quadrilateral. In such cases it can happen, that the intersection + // point found lies outside the element formed by the two triangles.) + + // A2. get corners + p0 = rRefElem.id(dim-1, sideOut, 0, 1); + p1 = rRefElem.id(dim-1, sideOut, 0, 2); + p2 = rRefElem.id(dim-1, sideOut, 0, 3); + + // if match: break + if(RayTriangleIntersection( GlobalIntersectionPointOut, bc0, bc1, t, + vCornerCoords[p0], vCornerCoords[p1], vCornerCoords[p2], + From, Direction)) + { + if(bPositiv && t >= 0.0) break; + else if(!bPositiv && t <= 0.0) break; + } + + // second triangle (only if 4 corners) + if(rRefElem.num(dim-1, sideOut, 0) == 3) continue; + + // B2. get corner number 1 as p2 and replace p1 by p2 + p1 = rRefElem.id(dim-1, sideOut, 0, 3); // added in order to create dijunct triangles filling the quadrilateral completely + p2 = rRefElem.id(dim-1, sideOut, 0, 0); + + // if match: break + if(RayTriangleIntersection( GlobalIntersectionPointOut, bc0, bc1, t, + vCornerCoords[p0], vCornerCoords[p1], vCornerCoords[p2], + From, Direction)) + { + if(bPositiv && t >= 0.0) break; + else if(!bPositiv && t <= 0.0) break; + } } // if not found diff --git a/ugbase/lib_disc/function_spaces/integrate.h b/ugbase/lib_disc/function_spaces/integrate.h index b5248484d..c9b076436 100644 --- a/ugbase/lib_disc/function_spaces/integrate.h +++ b/ugbase/lib_disc/function_spaces/integrate.h @@ -39,6 +39,7 @@ #include "common/common.h" +#include "integrate_tools.h" #include "lib_grid/tools/subset_group.h" #include "lib_disc/common/function_group.h" @@ -256,6 +257,163 @@ class StdIntegrand : public IIntegrand * associated attachment entry. * \returns value of the integral */ + + template + number IntegrateInside(SmartPtr spFineGridFct, + SmartPtr spCoarseGridFct, + int si, + typename domain_traits::position_accessor_type& aaPos, + IIntegrand& integrand, + int quadOrder, std::string quadType, + Grid::AttachmentAccessor< + typename domain_traits::grid_base_object, ANumber> + *paaElemContribs = NULL + ) + { + PROFILE_FUNC(); + + // reset the result + number integral = 0; + number integralOutside = 0; + + // set data for getting parten element + const int coarseTopLevel = spCoarseGridFct->dof_distribution()->grid_level().level(); + const int fineTopLevel = spFineGridFct->dof_distribution()->grid_level().level(); + SmartPtr spMG = spFineGridFct->domain()->grid(); + + // this is the base element type (e.g. Face). This is the type when the + // iterators above are dereferenciated. + typedef typename domain_traits::grid_base_object grid_base_object; + + // note: this iterator is for the base elements, e.g. Face and not + // for the special type, e.g. Triangle, Quadrilateral + TConstIterator iter = spFineGridFct->template begin(si); + TConstIterator iterEnd = spFineGridFct->template end(si); + + // get quad type + if(quadType.empty()) quadType = "best"; + QuadType type = GetQuadratureType(quadType); + + // accessing without dereferencing a pointer first is simpler... + Grid::AttachmentAccessor aaElemContribs; + if(paaElemContribs) + aaElemContribs = *paaElemContribs; + + // We'll reuse containers to avoid reallocations + std::vector > vCorner; + std::vector > vCornerCoarse; + std::vector > vGlobIP; + std::vector > vJT; + std::vector vValue; + + // iterate over all elements + for(; iter != iterEnd; ++iter) + { + // get element + grid_base_object* pElem = *iter; + + // get coarse element + GridObject* pParentElem = pElem; + if(coarseTopLevel < fineTopLevel){ + int parentLevel = spMG->get_level(pParentElem); + while(parentLevel > coarseTopLevel){ + pParentElem = spMG->get_parent(pParentElem); + parentLevel = spMG->get_level(pParentElem); + } + } + grid_base_object* pCoarseElem = (grid_base_object*)pParentElem; + + // get reference object id (i.e. Triangle, Quadrilateral, Tetrahedron, ...) + ReferenceObjectID roid = (ReferenceObjectID) pElem->reference_object_id(); + + // get quadrature Rule for reference object id and order + try{ + const QuadratureRule& rQuadRule + = QuadratureRuleProvider::get(roid, quadOrder, type); + + // get reference element mapping by reference object id + DimReferenceMapping& mapping + = ReferenceMappingProvider::get(roid); + + // number of integration points + const size_t numIP = rQuadRule.size(); + + // get all corner coordinates + CollectCornerCoordinates(vCorner, *pElem, aaPos, true); + CollectCornerCoordinates(vCornerCoarse, *pCoarseElem, aaPos, true); + + // skip all outside and cut elements! + const MathVector& center(0.2); + const number radius = 0.05; + bool outsideElem = false; + for ( size_t i = 0; i < vCornerCoarse.size(); ++i ) + { + number dist = 0.0; + for ( size_t d = 0; d < dim; ++d ) + dist += (vCornerCoarse[i][d]-center[d]) * (vCornerCoarse[i][d]-center[d]); + dist = sqrt(dist); + if ( (dist-radius) < 1e-10) + { + outsideElem = true; + } + } + if ( outsideElem ) + continue; + // update the reference mapping for the corners + mapping.update(&vCorner[0]); + + // compute global integration points + vGlobIP.resize(numIP); + mapping.local_to_global(&(vGlobIP[0]), rQuadRule.points(), numIP); + + // compute transformation matrices + vJT.resize(numIP); + mapping.jacobian_transposed(&(vJT[0]), rQuadRule.points(), numIP); + + // compute integrand values at integration points + vValue.resize(numIP); + try + { + integrand.values(&(vValue[0]), &(vGlobIP[0]), + pElem, &vCorner[0], rQuadRule.points(), + &(vJT[0]), + numIP); + } + UG_CATCH_THROW("Unable to compute values of integrand at integration point."); + + // reset contribution of this element + number intValElem = 0; + + // loop integration points + for(size_t ip = 0; ip < numIP; ++ip) + { + // get quadrature weight + const number weightIP = rQuadRule.weight(ip); + + // get determinate of mapping + const number det = SqrtGramDeterminant(vJT[ip]); + + // add contribution of integration point + intValElem += vValue[ip] * weightIP * det; + } + + // add to global sum + if ( outsideElem ) + integralOutside += intValElem; + else + integral += intValElem; + if(aaElemContribs.valid()) + aaElemContribs[pElem] = intValElem; + + }UG_CATCH_THROW("SumValuesOnElems failed."); + } // end elem + + + // return the summed integral contributions of all elements + return integral; + } + + template number Integrate(TConstIterator iterBegin, TConstIterator iterEnd, @@ -387,7 +545,37 @@ number IntegrateSubset(IIntegrand &spIntegrand, spIntegrand, quadOrder, quadType); } - + + + template + number IntegrateSubsetInside(SmartPtr > spIntegrand, + SmartPtr spFineGridFct, + SmartPtr spCoarseGridFct, + int si, int quadOrder, std::string quadType) + { + // integrate elements of subset + typedef typename TGridFunction::template dim_traits::const_iterator const_iterator; + + spIntegrand->set_subset(si); + /* + return IntegrateOnInnerBoundary + (spFineGridFct, + spCoarseGridFct, + si, + spFineGridFct->domain()->position_accessor(), + *spIntegrand, + quadOrder, quadType); + */ + return IntegrateInside + (spFineGridFct, + spCoarseGridFct, + si, + spFineGridFct->domain()->position_accessor(), + *spIntegrand, + quadOrder, quadType); + + } + template number IntegrateSubsets(IIntegrand &spIntegrand, @@ -457,6 +645,76 @@ number IntegrateSubsets(IIntegrand &spIntegrand, return value; } + + template + number IntegrateSubsetsInside(SmartPtr > spIntegrand, + SmartPtr spFineGridFct, + SmartPtr spCoarseGridFct, + const char* subsets, int quadOrder, + std::string quadType = std::string()) + { + // world dimensions + static const int dim = TGridFunction::dim; + + // read subsets + SubsetGroup ssGrp(spFineGridFct->domain()->subset_handler()); + if(subsets != NULL) + { + ssGrp.add(TokenizeString(subsets)); + if(!SameDimensionsInAllSubsets(ssGrp)) + UG_THROW("IntegrateSubsets: Subsets '"< dim) + UG_THROW("IntegrateSubsets: Dimension of subset is "<(spIntegrand, spFineGridFct, spCoarseGridFct, si, quadOrder, quadType); break; + case 2: value += IntegrateSubsetInside(spIntegrand, spFineGridFct, spCoarseGridFct, si, quadOrder, quadType); break; + case 3: value += IntegrateSubsetInside(spIntegrand, spFineGridFct, spCoarseGridFct, si, quadOrder, quadType); break; + default: UG_THROW("IntegrateSubsets: Dimension "< 1) + { + pcl::ProcessCommunicator com; + number local = value; + com.allreduce(&local, &value, 1, PCL_DT_DOUBLE, PCL_RO_SUM); + } +#endif + + // return the result + return value; + } + //////////////////////////////////////////////////////////////////////////////// // UserData Integrand @@ -1122,7 +1380,363 @@ number L2Error(const char* ExactSol, } #endif - + + template + class L2DiffInnerBoundaryIntegrand + : public StdIntegrand > + { + public: + /// world dimension of grid function + static const int worldDim = TGridFunction::dim; + + private: + SmartPtr m_spFineGridFct; + const size_t m_fineFct; + const LFEID m_fineLFEID; + const int m_fineTopLevel; + + SmartPtr m_spCoarseGridFct; + const size_t m_coarseFct; + const LFEID m_coarseLFEID; + const int m_coarseTopLevel; + + /// multigrid + SmartPtr m_spMG; + + public: + /// constructor (1 is fine grid function) + L2DiffInnerBoundaryIntegrand(SmartPtr spFineGridFct, size_t fineCmp, + SmartPtr spCoarseGridFct, size_t coarseCmp) + : m_spFineGridFct(spFineGridFct), m_fineFct(fineCmp), + m_fineLFEID(m_spFineGridFct->local_finite_element_id(m_fineFct)), + m_fineTopLevel(m_spFineGridFct->dof_distribution()->grid_level().level()), + m_spCoarseGridFct(spCoarseGridFct), m_coarseFct(coarseCmp), + m_coarseLFEID(m_spCoarseGridFct->local_finite_element_id(m_coarseFct)), + m_coarseTopLevel(m_spCoarseGridFct->dof_distribution()->grid_level().level()), + m_spMG(m_spFineGridFct->domain()->grid()), + numCoarseElemCut(0), numFineElemCut(0) + { + if(m_fineTopLevel < m_coarseTopLevel) + UG_THROW("L2DiffInnerBoundaryIntegrand: fine and top level inverted."); + + if(m_spFineGridFct->domain().get() != + m_spCoarseGridFct->domain().get()) + UG_THROW("L2DiffInnerBoundaryIntegrand: grid functions defined on different domains."); + }; + + /// sets subset + virtual void set_subset(int si) + { + if(!m_spFineGridFct->is_def_in_subset(m_fineFct, si)) + UG_THROW("L2DiffInnerBoundaryIntegrand: Grid function component" + <is_def_in_subset(m_coarseFct, si)) + UG_THROW("L2DiffInnerBoundaryIntegrand: Grid function component" + <::set_subset(si); + } + + + /// \copydoc IIntegrand::values + template + void evaluate(number vValue[], + const MathVector vFineGlobIP[], + GridObject* pFineElem, + const MathVector vCornerCoords[], + const MathVector vFineLocIP[], + const MathMatrix vJT[], + const size_t numIP) + { + const char* filename = "evaluate"; + std::string name(filename); + char ext[50]; sprintf(ext, ".txt"); + name.append(ext); + FILE* outputFile = fopen(name.c_str(), "a"); + + typedef typename TGridFunction::template dim_traits::grid_base_object Element; + + // get coarse element + GridObject* pCoarseElem = pFineElem; + if(m_coarseTopLevel < m_fineTopLevel){ + int parentLevel = m_spMG->get_level(pCoarseElem); + while(parentLevel > m_coarseTopLevel){ + pCoarseElem = m_spMG->get_parent(pCoarseElem); + parentLevel = m_spMG->get_level(pCoarseElem); + } + } + + typename domain_traits::position_accessor_type& aaPos = m_spCoarseGridFct->domain()->position_accessor(); + std::vector fine_vOriginalCornerID; + std::vector fine_vInterfaceID; + bool fineElemCut = false; + // get reference object id (i.e. Triangle, Quadrilateral, Tetrahedron, ...) + ReferenceObjectID fineROID = pFineElem->reference_object_id(); + std::vector > vCornerFine; + if ( !CollectCorners_FlatTop_2d(pFineElem, m_spMG, aaPos, vCornerFine, fine_vOriginalCornerID, fine_vInterfaceID, fineROID) ) + { + CollectCornerCoordinates(vCornerFine, *static_cast(pFineElem), *m_spFineGridFct->domain()); + // fill 'm_vOriginalCornerID' for setting origSH later on: + for ( size_t i = 0; i < vCornerFine.size(); ++i ) + fine_vOriginalCornerID.push_back(i); + } + else + { + numFineElemCut++; + + fineElemCut = true; + + } + + // get corner coordinates + std::vector coarse_vOriginalCornerID; + std::vector coarse_vInterfaceID; + ReferenceObjectID coarseROID = pCoarseElem->reference_object_id(); + std::vector > vCornerCoarse; + if ( !CollectCorners_FlatTop_2d(pCoarseElem, m_spMG, aaPos, vCornerCoarse, coarse_vOriginalCornerID, coarse_vInterfaceID, coarseROID) ) + { + if ( fineElemCut ) + UG_THROW(" not possible: fineElemCut = true && coarseElemCut = false!\n"); + CollectCornerCoordinates(vCornerCoarse, *static_cast(pCoarseElem), *m_spCoarseGridFct->domain()); + // fill 'm_vOriginalCornerID' for setting origSH later on: + for ( size_t i = 0; i < vCornerCoarse.size(); ++i ) + coarse_vOriginalCornerID.push_back(i); + } + else + { + numCoarseElemCut++; + } + + + // get Reference Mapping + DimReferenceMapping& map + = ReferenceMappingProvider::get(coarseROID, vCornerCoarse); + + std::vector > vCoarseLocIP; + vCoarseLocIP.resize(numIP); + for(size_t ip = 0; ip < vCoarseLocIP.size(); ++ip) VecSet(vCoarseLocIP[ip], 0.0); + map.global_to_local(&vCoarseLocIP[0], vFineGlobIP, numIP); + + try{ + // get trial space + const LocalShapeFunctionSet& rFineLSFS = + LocalFiniteElementProvider::get(fineROID, m_fineLFEID); + const LocalShapeFunctionSet& rCoarseLSFS = + LocalFiniteElementProvider::get(coarseROID, m_coarseLFEID); + + // get multiindices of element + std::vector vFineMI, vCoarseMI; + // m_fineFct = u,v,p! + m_spFineGridFct->dof_indices(pFineElem, m_fineFct, vFineMI); + m_spCoarseGridFct->dof_indices(pCoarseElem, m_coarseFct, vCoarseMI); + + // loop all integration points + for(size_t ip = 0; ip < numIP; ++ip) + { + // compute approximated solution at integration point + number fineSolIP = 0.0; + number sumShapeFine = 0.0; + + for(size_t sh = 0; sh < vCornerFine.size(); ++sh) + { + bool bContinue1 = false; + // solution value for outside velocity := 0.0! + if ( m_fineFct < worldDim ) + if ( is_insideParticle(vCornerFine[sh], 0) ) + bContinue1 = true; //continue; + + bool bContinue2 = false; + if ( m_fineFct < worldDim ) + { + for ( size_t i = 0; i < fine_vInterfaceID.size(); ++i ) + if ( sh == fine_vInterfaceID[i] ) + bContinue2 = true; //continue; + } + if ( (bContinue1 && !bContinue2) ) + { + for ( size_t i = 0; i < fine_vInterfaceID.size(); ++i ) + UG_LOG("vInterface = " << fine_vInterfaceID[i] << "\n"); + UG_LOG("sh = " << sh << "\n"); + + UG_THROW("case1: error for criterion of continuing solution on FINE interface!\n"); + } + if ( (!bContinue1 && bContinue2) ) + { + number err = get_insideParticle(vCornerFine[sh], 0); + UG_LOG("err = " << err << "\n"); + if ( is_insideParticle(vCornerFine[sh], 0) ) + {UG_LOG("true\n");} + else {UG_LOG("false\n");} + for ( size_t i = 0; i < fine_vInterfaceID.size(); ++i ) + UG_LOG("vInterface = " << fine_vInterfaceID[i] << "\n"); + UG_LOG("sh = " << sh << "\n"); + + UG_THROW("case2: error for criterion of continuing solution on FINE interface!\n"); + } + + // get value at shape point (e.g. corner for P1 fct) + const size_t origSH = fine_vOriginalCornerID[sh]; + number val; + if ( bContinue1 && bContinue2 ) + { + val = get_value(m_spFineGridFct, m_fineTopLevel, m_fineFct, vCornerFine[sh]); + /* + MathVector RotVec; + RotVec[0] = -vCornerFine[sh][1]; + RotVec[1] = vCornerFine[sh][0]; + if ( m_fineFct == 0 ) + val = 0.3; //-RotVec[m_fineFct]*0.5; + if ( m_fineFct == 1 ) + val = 0.0; + */ + } + else val = DoFRef(*m_spFineGridFct, vFineMI[origSH]); + + // if ( vCornerFine.size() == 4 ) UG_LOG("val = " << val << "\n"); + + // add shape fct at ip * value at shape + fineSolIP += val * rFineLSFS.shape(sh, vFineLocIP[ip]); + sumShapeFine += rFineLSFS.shape(sh, vFineLocIP[ip]); + + if ( 0 ) //vCornerFine.size() == 4 ) + { + UG_LOG("sh = " << sh << "\n"); + UG_LOG("origSH = " << origSH << "\n"); + UG_LOG("vFineMI[" << origSH << " = " << vFineMI[origSH] << "\n"); + UG_LOG("m_fineFct = " << m_fineFct << "\n"); + UG_LOG("shapeFine = " << rFineLSFS.shape(sh, vFineLocIP[ip]) << "\n"); + + } + } + + number coarseSolIP = 0.0; + number sumShapeCoarse = 0.0; + for(size_t sh = 0; sh < vCornerCoarse.size(); ++sh) + { + bool bContinue1 = false; + // solution value for outside velocity := 0.0! + if ( m_coarseFct < worldDim ) + if ( is_insideParticle(vCornerCoarse[sh], 0) ) + bContinue1 = true; //continue; + + bool bContinue2 = false; + if ( m_coarseFct < worldDim ) + { + for ( size_t i = 0; i < coarse_vInterfaceID.size(); ++i ) + if ( sh == coarse_vInterfaceID[i] ) + bContinue2 = true; //continue; + } + + if ( (bContinue1 && !bContinue2) || (!bContinue1 && bContinue2) ) + UG_THROW("error for criterion of continuing solution on COARSE interface!\n"); + + + // get value at shape point (e.g. corner for P1 fct) + const size_t origSH = coarse_vOriginalCornerID[sh]; + number val; + if ( bContinue1 && bContinue2 ) + { + val = get_value(m_spCoarseGridFct, m_coarseTopLevel, m_coarseFct, vCornerCoarse[sh]); + /* + MathVector RotVec; + RotVec[0] = -vCornerCoarse[sh][1]; + RotVec[1] = vCornerCoarse[sh][0]; + if ( m_coarseFct == 0 ) + val = 0.3; // -RotVec[m_coarseFct]*0.5; + if ( m_coarseFct == 1 ) + val = 0.0; + */ + } + else val = DoFRef(*m_spCoarseGridFct, vCoarseMI[origSH]); + + + // add shape fct at ip * value at shape + coarseSolIP += val * rCoarseLSFS.shape(sh, vCoarseLocIP[ip]); + sumShapeCoarse += rCoarseLSFS.shape(sh, vCoarseLocIP[ip]); + + if ( 0 ) //vCornerCoarse.size() == 4 ) + { + UG_LOG("sh = " << sh << "\n"); + UG_LOG("origSH = " << origSH << "\n"); + UG_LOG("vCoarseMI[" << origSH << " = " << vCoarseMI[origSH] << "\n"); + UG_LOG("m_coarseFct = " << m_coarseFct << "\n"); + UG_LOG("shapeCoarse = " << rCoarseLSFS.shape(sh, vCoarseLocIP[ip]) << "\n"); + + } + } + + + if ( 0 ) //vCoarseMI[0][1] == 2 ) + if ( vCornerCoarse.size() == 4 ) + { + /* UG_LOG("trans[0] = " << DoFRef(*m_spFineGridFct, DoFIndex(3029,0)) << "\n"); + UG_LOG("trans[1] = " << DoFRef(*m_spFineGridFct, DoFIndex(3029,1)) << "\n"); + UG_LOG("rot[0] = " << DoFRef(*m_spFineGridFct, DoFIndex(12,0)) << "\n"); + UG_LOG("rot[1] = " << DoFRef(*m_spFineGridFct, DoFIndex(12,1)) << "\n"); + */ + UG_LOG("sumShapeFine = " << sumShapeFine << "\n"); + UG_LOG("sumShapeCoarse = " << sumShapeCoarse << "\n"); + UG_THROW("vCoarseMI[" << 0 << " = " << vCoarseMI[0] << "\n"); + } + + // get squared of difference + vValue[ip] = (coarseSolIP - fineSolIP); + vValue[ip] *= vValue[ip]; + + } + + } + UG_CATCH_THROW("L2ErrorIntegrand::evaluate: trial space missing."); + fclose(outputFile); + }; + + size_t numCoarseElemCut; + size_t numFineElemCut; + }; + + + + + template + number L2ErrorInside(SmartPtr spGridFct1, const char* cmp1, + SmartPtr spGridFct2, const char* cmp2, + int quadOrder, const char* subsets) + { + // get function id of name + const size_t fct1 = spGridFct1->fct_id_by_name(cmp1); + const size_t fct2 = spGridFct2->fct_id_by_name(cmp2); + + // check that function exists + if(fct1 >= spGridFct1->num_fct()) + UG_THROW("L2Error: Function space does not contain" + " a function with name " << cmp1 << "."); + if(fct2 >= spGridFct2->num_fct()) + UG_THROW("L2Error: Function space does not contain" + " a function with name " << cmp2 << "."); + + // get top level of gridfunctions + const int level1 = spGridFct1->dof_distribution()->grid_level().level(); + const int level2 = spGridFct2->dof_distribution()->grid_level().level(); + + // check + if(level1 > level2){ + SmartPtr > spIntegrand + = make_sp(new L2DiffInnerBoundaryIntegrand(spGridFct1, fct1, spGridFct2, fct2)); + return sqrt(IntegrateSubsetsInside(spIntegrand, spGridFct1, spGridFct2, subsets, quadOrder)); + }else{ + UG_LOG("level1 = " << level1 << ", level2 = " << level2 << "\n"); + SmartPtr > spIntegrand + = make_sp(new L2DiffInnerBoundaryIntegrand(spGridFct2, fct2, spGridFct1, fct1)); + return sqrt(IntegrateSubsetsInside(spIntegrand, spGridFct2, spGridFct1, subsets, quadOrder)); + } + } + + template + number L2ErrorInside(SmartPtr spGridFct1, const char* cmp1, + SmartPtr spGridFct2, const char* cmp2, + int quadOrder) + { + return L2ErrorInside(spGridFct1, cmp1, spGridFct2, cmp2, quadOrder, NULL); + } //////////////////////////////////////////////////////////////////////////////// @@ -1416,7 +2030,7 @@ number GridFunctionDistance2(TGridFunction& spGridFct1, const char* cmp1, const int level1 = spGridFct1.dof_distribution()->grid_level().level(); const int level2 = spGridFct2.dof_distribution()->grid_level().level(); - // w/ weights + // w/ weights if(level1 > level2){ TDistIntegrand spIntegrand(spGridFct1, fct1, spGridFct2, fct2, spWeights, distAvg12); return IntegrateSubsets(spIntegrand, spGridFct1, subsets, quadOrder); @@ -1767,6 +2381,7 @@ class L2DistIntegrand } UG_CATCH_THROW("L2DistIntegrand::evaluate: trial space missing."); + } }; diff --git a/ugbase/lib_disc/function_spaces/integrate_tools.h b/ugbase/lib_disc/function_spaces/integrate_tools.h new file mode 100644 index 000000000..e992ed796 --- /dev/null +++ b/ugbase/lib_disc/function_spaces/integrate_tools.h @@ -0,0 +1,1322 @@ +/* + * integrate_tools.h + * + * Created on: 03.07.2015 + * Author: suze + */ + +#ifndef INTEGRATE_TOOLS_H_ +#define INTEGRATE_TOOLS_H_ + +namespace ug{ + +template +number get_value(SmartPtr spGridFct, const int level, const size_t fct, const MathVector Corner) +{ + std::vector vTransInd(6); + vTransInd[0] = 0; + vTransInd[1] = 143; + vTransInd[2] = 549; + vTransInd[3] = 3029; + vTransInd[4] = 8529; + vTransInd[5] = 62201; + + std::vector vRotInd(6); + vRotInd[0] = 0; + vRotInd[1] = 12; + vRotInd[2] = 12; + vRotInd[3] = 12; + vRotInd[4] = 2153; + vRotInd[5] = 2153; + + MathVector RotVec; + RotVec[0] = -Corner[1]; + RotVec[1] = Corner[0]; + + const size_t transInd = vTransInd[level]; + const size_t rotInd = vRotInd[level]; + + const number transVel = DoFRef(*spGridFct, DoFIndex(transInd, fct)); + const number rotVel = DoFRef(*spGridFct, DoFIndex(rotInd, fct)); + + //UG_LOG("transVel = " << transVel << ", rotVel = " << rotVel << "\n"); + + const number val = transVel + rotVel*RotVec[fct]; + + return val; +} + +template +bool set_nearInterface(MathVector vrtPos, int prtIndex) +{ + const number radius = 0.05; + const MathVector center(0.2); + const number threshold = 1e-9; + // ToDo threshold! + + // default value of threshold = 0.0 => do nothing in this case +// if (threshold == 0.0) +// return false; + + const number dist = VecDistance(vrtPos, center); + + if (fabs(dist - radius) < threshold) + return true; + + return false; +} + + +template +number get_insideParticle(MathVector vrtPos, int prtIndex) +{ + const number radius = 0.05; + const MathVector center(0.2); + + bool outsideFluid = false; + if ( (VecDistance(vrtPos, center)-radius) < 1e-10) + { + outsideFluid = true; + } + else + { + outsideFluid = set_nearInterface(vrtPos, prtIndex); + } + + return (VecDistance(vrtPos, center)-radius); +} + +template +bool is_insideParticle(MathVector vrtPos, int prtIndex) +{ + const number radius = 0.05; + const MathVector center(0.2); + + bool outsideFluid = false; + if ( (VecDistance(vrtPos, center)-radius) < 1e-10) + outsideFluid = true; + else + outsideFluid = set_nearInterface(vrtPos, prtIndex); + + return outsideFluid; +} + +template +number get_LSvalue_byPosition(MathVector vrtPos, int PrtIndex) +{ + const number radius = 0.05; + const MathVector center(0.2); + + MathVector localCoords; + VecSubtract(localCoords, vrtPos, center); + + number dist = VecDot(localCoords, localCoords); + dist = sqrt(dist); + + return radius - dist; +} + +template +bool get_LineCircle_Intersection(MathVector& Intersect, Vertex* vrtOutsideCirc, + Vertex* vrtInsideCirc, int PrtIndex, + typename domain_traits::position_accessor_type& aaPos) +{ + const number radius = 0.05; + const MathVector center(0.2); + + //if ( dim == 3 ) UG_THROW("in 'get_LineCircle_Intersection()': not implemented for 3d case!\n"); + + /////////////////////////////////////////////////////////////////////////////////////// + // + // 'vrtPosOut':= the starting point of the ray, + // 'vrtPosIn' := the end point of the ray, + // 'center' := the center of sphere you're testing against + // 'radius' := the radius of that sphere + // 'lineDir' := direction vector of ray from start to end + // 'rayDir' := direction vector of ray from center to start + // + // Ansatz: + // (1) Intersect = vrtPosOut + alpha*lineDir + // (2) Intersect - center = radius + // + // => (1) Intersect[0] = vrtPosOut[0] + alpha*lineDir[0] + // Intersect[1] = vrtPosOut[1] + alpha*lineDir[1] + // => (2) (Intersect[0] - center[0])^2 + (Intersect[1] - center[1])^2 = radius^2 + // + // Plug (1) into (2) => ... => quadratic equation for alpha: + // + // alpha^2 * + alpha * 2* + ( -radius^2 ) = 0 + // + // -> a = , b = , c = - radius^2 + // + // + // => from (1): Intersect = vrtPosOut + alpha*(vrtPosIn - vrtPosOut) + /////////////////////////////////////////////////////////////////////////////////////// + + number alpha; + + const MathVector& vrtPosOut = aaPos[vrtOutsideCirc]; + const MathVector& vrtPosIn = aaPos[vrtInsideCirc]; + + MathVector lineDir; + MathVector rayDir; + +// lineDir = vrtPosIn - vrtPosOut; + VecSubtract(lineDir, vrtPosIn, vrtPosOut); +// rayDir = vrtPosOut - center; + VecSubtract(rayDir, vrtPosOut, center); + + const number a = VecDot(lineDir, lineDir); + const number b = 2.0 * VecDot(lineDir, rayDir); + const number c = VecDot(vrtPosOut, vrtPosOut) + VecDot(center, center) + - 2 * VecDot(vrtPosOut, center) - radius * radius; + + const number discriminant = b * b - 4 * a * c; + +// check that 'vrtPosOut' and 'vrtPosIn' really lie on different sides of the circle: + if (discriminant < -1e-8) + UG_THROW("Value of discriminant = " << discriminant << "\n"); + + +// discriminant = 0! + const number alpha1 = (-b - sqrt(discriminant)) / (2.0 * a); + const number alpha2 = (-b + sqrt(discriminant)) / (2.0 * a); + + if (alpha1 <= alpha2) + alpha = alpha1; + else + alpha = alpha2; + + if (alpha < 0 || (alpha - 1.0) > 1e-8) + UG_THROW( + "Error in 'get_LineCircle_Intersection()': alpha not valid; should lie between 0 and 1: " << alpha << "\n"); + + for (size_t d = 0; d < dim; ++d) + Intersect[d] = vrtPosOut[d] + alpha * lineDir[d]; + + return true; +} +/* +bool isIncluded2(const size_t newID, std::vector vInterfaceID) +{ + for ( size_t i = 0; i < vInterfaceID.size(); ++i) + if ( vInterfaceID[i] == newID ) + return true; + + return false; +} +*/ +/* +void reset_sh_if_on_interface(size_t& sh, + std::vector vInterfaceID, + std::vector& vOriginalCornerID) +{ + for ( size_t i = 0; i < vInterfaceID.size(); ++i) + if ( vInterfaceID[i] == sh ) + sh = vOriginalCornerID[i]; + +} +*/ +template +bool isIncluded(std::vector > vCheckList, MathVector checkPoint) +{ + for(size_t i = 0; i < vCheckList.size(); ++i) + { + bool isEqual = true; + + if ( VecDistance(vCheckList[i],checkPoint) > 1e-10) + isEqual = false; + + if ( isEqual ) + return true; + + } + + return false; +} + +template +ReferenceObjectID set_roid_2d(const int numCo) +{ + ReferenceObjectID roid; + + switch(numCo) + { + case 0: roid = ROID_UNKNOWN; break; + case 3: roid = ROID_TRIANGLE; break; + case 4: roid = ROID_QUADRILATERAL; break; + + default: throw(UGError("during switch in 'set_roid_2d()': " + "m_numCo invalid => default case chosen")); + } + return roid; + +} + +template +ReferenceObjectID set_roid_3d(const int numCo) +{ + ReferenceObjectID roid; + + switch(numCo) + { + case 0: roid = ROID_UNKNOWN; break; + case 4: roid = ROID_TETRAHEDRON; break; + case 5: roid = ROID_PYRAMID; break; + case 6: roid = ROID_PRISM; break; + + default: throw(UGError("during switch in 'set_roid_3d()': " + "m_numCo invalid => default case chosen")); + } + return roid; + +} + +// parameter 'normal' is the direction from the triangle into the inner of the prism +template +bool isCCW(std::vector > vCornerCoords, MathVector normal) +{ + + MathVector e1, e2; + VecSubtract(e1, vCornerCoords[1], vCornerCoords[0]); + VecSubtract(e2, vCornerCoords[2], vCornerCoords[0]); + + MathVector n; + VecCross(n, e1, e2); + VecNormalize(n,n); + VecNormalize(normal,normal); + + if ( fabs(VecDot(n, normal)) < 1e-6 ) + UG_THROW("in 'isCCW()': vectors are perpendicular.\n"); + + if ( VecDot(n, normal) > 0 ) return true; // CCW + else return false; + +} + +template +ReferenceObjectID reset_sh_if_on_interface(size_t& sh, + std::vector vInterfaceID, + std::vector& vOriginalCornerID) +{ + + for ( size_t i = 0; i < vInterfaceID.size(); ++i) + if ( vInterfaceID[i] == sh ) + sh = vOriginalCornerID[i]; + + ReferenceObjectID roid; + int numCo = 4; + switch(numCo) + { + case 0: roid = ROID_UNKNOWN; break; + case 4: roid = ROID_TETRAHEDRON; break; + case 5: roid = ROID_PYRAMID; break; + case 6: roid = ROID_PRISM; break; + + default: throw(UGError("during switch in 'set_roid_3d()': " + "m_numCo invalid => default case chosen")); + } + + return roid; + +} + +template +void ResortQuadrilateral(std::vector, size_t > > vInsideCorners, + std::vector, size_t > > vOutsideCorners, + MathVector normalDir, + std::vector >& m_vCornerCoords, + std::vector& m_vOriginalCornerID, + std::vector& m_vInterfaceID) +{ +// some checks: + if ( vOutsideCorners.size() != 2 ) UG_THROW("vOutsideCorners.size() has to be 2 in 2d case, but is " << vOutsideCorners.size() << ".\n"); + if ( vInsideCorners.size() != 2 ) UG_THROW("vInsideCorners.size() has to be 2 in 2d case, but is " << vInsideCorners.size() << ".\n"); + if ( vOutsideCorners[0].second != vOutsideCorners[1].second ) UG_THROW("Outside indices must be identical!\n"); + +//////////////////////////////////////////////////////////////////////////////////////////// +// 1) Copy 'vOutsideCorners'/'vOutsideCorners' to 'm_vCornerCoords' in special order: +// -> ordering: 1. insideCorner, 2./3. outsideCorner, 4. insideCorner +//////////////////////////////////////////////////////////////////////////////////////////// + + m_vCornerCoords.clear(); m_vCornerCoords.resize(4); + m_vOriginalCornerID.clear(); m_vOriginalCornerID.resize(4); +// fill with insideCorners+indices: + m_vCornerCoords[0] = vInsideCorners[0].first; + m_vOriginalCornerID[0] = vInsideCorners[0].second; + + m_vCornerCoords[3] = vInsideCorners[1].first; + m_vOriginalCornerID[3] = vInsideCorners[1].second; + +// fill with outsideCorners+indices: + m_vCornerCoords[1] = vOutsideCorners[0].first; + m_vOriginalCornerID[1] = vOutsideCorners[0].second; + + m_vCornerCoords[2] = vOutsideCorners[1].first; + m_vOriginalCornerID[2] = vOutsideCorners[1].second; + +// remember outside Index in order to fill 'vm_vInterfaceID' after re-ordering. + size_t outInd = vOutsideCorners[0].second; + +//////////////////////////////////////////////////////////////////////////////////////////// +// 2) Check for potential cross-ordering or not-CCW +//////////////////////////////////////////////////////////////////////////////////////////// + MathVector<3> vNormOut1, vNormOut2; + std::vector > vCornerCoordsBlow; vCornerCoordsBlow.resize(4); + for ( size_t i = 0; i < m_vCornerCoords.size(); ++i ) + { + for ( size_t d = 0; d < dim; ++d ) + vCornerCoordsBlow[i][d] = m_vCornerCoords[i][d]; + vCornerCoordsBlow[i][2] = 0.0; + } + + CalculateTriangleNormalNoNormalize(vNormOut1, vCornerCoordsBlow[0], vCornerCoordsBlow[1], vCornerCoordsBlow[2]); + CalculateTriangleNormalNoNormalize(vNormOut2, vCornerCoordsBlow[2], vCornerCoordsBlow[3], vCornerCoordsBlow[0]); + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// Check 1 - cross-ordering +// VecDot(vNormOut1,vNormOut2) < 0 => corners of quadrilateral are not ordered along the +// endges, i.e. across the diagonal => switch order of the two outideCorners, i.e. index [1],[2] +///////////////////////////////////////////////////////////////////////////////////////////////////////// + if ( VecDot(vNormOut1, vNormOut2) < 0 ) + { + MathVector bufferCoord = m_vCornerCoords[1]; + size_t bufferInd = m_vOriginalCornerID[1]; + + m_vCornerCoords[1] = m_vCornerCoords[2]; + m_vOriginalCornerID[1] = m_vOriginalCornerID[2]; + + m_vCornerCoords[2] = bufferCoord; + m_vOriginalCornerID[2] = bufferInd; + } + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// Check 2 - CCW? +// VecDot(vNormOut1,zDir) < 0 => corners of quadrilateral are not CCW: +///////////////////////////////////////////////////////////////////////////////////////////////////////// + for ( size_t i = 0; i < m_vCornerCoords.size(); ++i ) + { + for ( size_t d = 0; d < dim; ++d ) + vCornerCoordsBlow[i][d] = m_vCornerCoords[i][d]; + if ( dim == 2 ) vCornerCoordsBlow[i][2] = 0.0; + + + } + CalculateTriangleNormalNoNormalize(vNormOut1, vCornerCoordsBlow[0], vCornerCoordsBlow[1], vCornerCoordsBlow[2]); + CalculateTriangleNormalNoNormalize(vNormOut2, vCornerCoordsBlow[2], vCornerCoordsBlow[3], vCornerCoordsBlow[0]); + + if ( VecDot(vNormOut1, vNormOut2) < 0 ) UG_THROW("check 1 failed after second check!\n"); + + +// pure copy of 'normalDir' data because of data type inconsistence (MathVector<3> vs. MathVector) + MathVector<3> _normalDir; + for ( size_t i = 0; i < 2; ++i ) + _normalDir[i] = normalDir[i]; + if ( dim == 2 ) _normalDir[2] = 1.0; + if ( dim == 3 ) _normalDir[2] = normalDir[2]; + + if ( VecDot(vNormOut1, _normalDir) < 0 ) + { + + MathVector bufferCoord = m_vCornerCoords[1]; + size_t bufferInd = m_vOriginalCornerID[1]; + + m_vCornerCoords[1] = m_vCornerCoords[3]; + m_vOriginalCornerID[1] = m_vOriginalCornerID[3]; + + m_vCornerCoords[3] = bufferCoord; + m_vOriginalCornerID[3] = bufferInd; + } + +// fill 'vInterfaceID': + m_vInterfaceID.clear(); + for ( size_t i = 0; i < m_vOriginalCornerID.size(); ++i ) + if ( m_vOriginalCornerID[i] == outInd ) + m_vInterfaceID.push_back(i); + +} + +template +bool CollectCorners_FlatTop_2d(GridObject* elem, + SmartPtr m_spMG, + typename domain_traits::position_accessor_type& aaPos, + std::vector >& m_vCornerCoords, + std::vector& m_vOriginalCornerID, + std::vector& m_vInterfaceID, + ReferenceObjectID& coarseROID +) +{ + ////////////////////////////////////////////// + // 1) fill vector with fluid corners: + ////////////////////////////////////////////// + + m_vCornerCoords.clear(); + m_vInterfaceID.clear(); + m_vOriginalCornerID.clear(); + +// buffer vectors for (cornerCoords, cornerIndex) + std::vector, size_t > > vOutsideCorners; + std::vector, size_t > > vInsideCorners; + std::vector, size_t > > vNearIntCorners; + +// collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *m_spMG, elem); + + + // get prtIndex: + bool isFTVertex = false; + size_t numCoOut = 0; + + for(size_t i = 0; i < vVertex.size(); ++i) + { + // remember boolian for check, weather there existe at least one vertex, which is FT! + isFTVertex = is_insideParticle(aaPos[vVertex[i]], 0); + if ( isFTVertex ) + numCoOut++; + } + + + if ( !isFTVertex || numCoOut == vVertex.size() ) + return false; + + + // collect all edges of the element + std::vector vEdges; + CollectEdgesSorted(vEdges, *m_spMG, elem); + + // loop vertices + ////////////////////////////////////////////// + // REMARK: + // order is the same as in 'vCornerCoords', therefore we can be sure, that the + // order of the new 'vCornerIBCoords' will be consistent with the grid standard + ///////////////////////// ///////////////////// + + bool bNearInterface = false; + for(size_t i = 0; i < vVertex.size(); ++i) + { + + // get element + Vertex* vrtRoot = vVertex[i]; + ////////////////////////////////////////////// + // case 1: + // vertex insideFluid + // => Position und index puschen + if ( ! is_insideParticle(aaPos[vrtRoot], 0) ) + { + + if ( set_nearInterface(aaPos[vrtRoot], 0) ) + { + UG_THROW("NearInterface BUT !is_FT => neuerdings Fehler!!....\n"); + } + else + { + m_vCornerCoords.push_back(aaPos[vrtRoot]); + m_vOriginalCornerID.push_back(i); + + vInsideCorners.push_back(std::make_pair(aaPos[vrtRoot], i)); + } + + } + ////////////////////////////////////////////// + // case 2: + // vertex = FT + ON interface + // => KEINE Berechnung von 'intersectionPoint' notwendig! -> pushen und alten index pushen + + // REMARK: is_nearInterfaceVerx = false per default, if m_vThresholdOnLevel = 0.0 + else if ( set_nearInterface(aaPos[vrtRoot], 0) ) + { + + bNearInterface = true; + m_vCornerCoords.push_back(aaPos[vrtRoot]); + m_vOriginalCornerID.push_back(i); + m_vInterfaceID.push_back(m_vCornerCoords.size()-1); // attention: push AFTER 'm_vCornerCoords.push_back()'!! + + vOutsideCorners.push_back(std::make_pair(aaPos[vrtRoot], i)); + vNearIntCorners.push_back(std::make_pair(aaPos[vrtRoot], i)); + + } + ////////////////////////////////////////////// + // case 3: + // vertex 'outsideFluid' + // => NEUE Position berechen+pushen und alten index pushen + else + { + + ////////////////////////////////////////////////////////////////////////////////////////// + // loop alle edges, die interface schneiden und damit einen neuen intersectionPnt + // beitragen zum damit assoziierten alten index + for(size_t e = 0; e < vEdges.size(); ++e) + { + + Edge* edge = vEdges[e]; + std::vector vVertexEdge; + CollectVertices(vVertexEdge, *m_spMG, edge); + if ( vVertexEdge.size() != 2 ) + UG_THROW("error in collecting vertices associated to an edge!....EXIT!...\n"); + + Vertex* vrt1 = vVertexEdge[0]; + Vertex* vrt2 = vVertexEdge[1]; + + MathVector intersectionPnt; + + /////////////////////////////////////////////////////////////////// + // lies vrtRoot on a cutted edge? + /////////////////////////////////////////////////////////////////// + // case1: vrtRoot is intersectionPnt with insideCorner = near_interface_corner => remove! + if ( set_nearInterface(aaPos[vrt2], 0) || set_nearInterface(aaPos[vrt1], 0) ) + { bNearInterface = true; continue; } + // case2: vert2 = outsideParticle && vrt1 = insideParticle: + else if ( vrtRoot == vrt1 && !is_insideParticle(aaPos[vrt2], 0) ){ + get_LineCircle_Intersection(intersectionPnt, vrt2, vrt1, 0, aaPos); + } + // case3: vrt1 = outsideParticle && vrt2 = insideParticle: + else if ( vrtRoot == vrt2 && !is_insideParticle(aaPos[vrt1], 0) ) + { get_LineCircle_Intersection(intersectionPnt, vrt1, vrt2, 0, aaPos);} + else + {continue;} + + // check for correct inersectionPnt + if ( fabs(get_LSvalue_byPosition(intersectionPnt, 0)) > 1e-6 ) + UG_THROW("in 'CollectIBCorners2d()': Error in computation of 'intersectionPnt':\n " + " intersectionPnt = " << intersectionPnt << "\n distance from interace = " << fabs(get_LSvalue_byPosition(intersectionPnt, 0)) << "\n"); + + + /////////////////////////////////////////////////////////////////// + // only push_back, if not included yet! + // -> can be ONLY the case, if the intersectionPoint is a node + if ( ! isIncluded(m_vCornerCoords, intersectionPnt) ) + { + + m_vCornerCoords.push_back(intersectionPnt); + m_vOriginalCornerID.push_back(i); + m_vInterfaceID.push_back(m_vCornerCoords.size()-1); // attention: push AFTER 'm_vCornerCoords.push_back()'!! + + vOutsideCorners.push_back(std::make_pair(intersectionPnt, i)); + } + + + } // end edge-loop + + } // end else-case + + } // end vrt-loop + +//////////////////////////////////////////////////////////////////////////////////////////// +// Postprecessing for quadrilaterals ( <=> vOutsideCorners == 2 ) +// (vInsideCorners.size() == 2) && (bNearInterface) => ALL nodes insideFluid, BUT one ON surface +// => no Quadrilateral, but Triangle!! +//////////////////////////////////////////////////////////////////////////////////////////// + MathVector normalDir(0.0); + if ( (m_vCornerCoords.size() == 4) && (!bNearInterface) && (dim == 2) ) + { + ResortQuadrilateral(vInsideCorners, vOutsideCorners, normalDir, m_vCornerCoords, m_vOriginalCornerID, m_vInterfaceID); + } + else if ( bNearInterface ) + { + // Quadrilateral -> Triangle + if ( vInsideCorners.size() == 1 ) // case 1 + { + // do nothing, since re-sorting not necessary...??? + } + // skip whole element, since only FT points are included + else if ( vInsideCorners.size() == 0 ) + UG_THROW("in 'CollectCorners_FlatTop_2d()': vInsideCorners.size() " + "= " << vInsideCorners.size() << "not possible!\n"); + } + + const int numCo = m_vCornerCoords.size(); + + if ( dim == 2 ) + coarseROID = set_roid_2d(numCo); + + if ( numCo == 0 ) + UG_THROW("hmmm: coarseROID = " << coarseROID << "\n"); + + return true; + +} + + +template +bool CollectCorners_FlatTop_Prism3(GridObject* elem, + SmartPtr m_spMG, + typename domain_traits::position_accessor_type& aaPos, + std::vector >& m_vCornerCoords, + std::vector& m_vOriginalCornerID, + std::vector& m_vInterfaceID, + ReferenceObjectID& coarseROID) +{ +/////////////////////////////////////////////////////////////////// +// 1) push_back into 'vInsideCorners' +// 2) collect according outsideCorner (lying on the commom edge) +// 3) push_back into 'vOutsideCorners' +/////////////////////////////////////////////////////////////////// + + bool output = false; + + if ( output ) UG_LOG("_________________________ begin 'CollectIBCorners3d_Prism3()' ______________________________\n\n"); + + m_vCornerCoords.clear(); + m_vInterfaceID.clear(); + m_vOriginalCornerID.clear(); + + std::vector > vOutsideCorners; + std::vector > vInsideCorners; + +// collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *m_spMG, elem); + + // collect all edges of the element + std::vector vEdges; + CollectEdgesSorted(vEdges, *m_spMG, elem); + + // loop vertices + size_t outsideInd; + for(size_t i = 0; i < vVertex.size(); ++i) + { + // get element + Vertex* vrtRoot = vVertex[i]; + + if ( ! is_insideParticle(aaPos[vrtRoot], 0) ) + { + /////////////////////////////////////////////////////////////////// + // 1) push_back into 'vInsideCorners' + vInsideCorners.push_back(aaPos[vrtRoot]); + m_vOriginalCornerID.push_back(i); + + /////////////////////////////////////////////////////////////////// + // 2) collect according outsideCorner (lying on the commom edge) + bool outsideCornerFound = false; + MathVector intersectionPnt; + for(size_t e = 0; e < vEdges.size(); ++e) + { + Edge* edge = vEdges[e]; + std::vector vVertexEdge; + CollectVertices(vVertexEdge, *m_spMG, edge); + if ( vVertexEdge.size() != 2 ) + UG_THROW("in 'NEWcall_Extrapolation': error in collecting vertices associated to an edge!....EXIT!...\n"); + Vertex* vrt1 = vVertexEdge[0]; + Vertex* vrt2 = vVertexEdge[1]; + + // lies vrtRoot on a cutted edge? + // case1: vrt1 = outsideParticle && vrt2 = insideParticle: + if ( vrtRoot == vrt1 && is_insideParticle(aaPos[vrt2], 0) ) + {outsideCornerFound = get_intersection_point(intersectionPnt, vrt1, vrt2);} + // case2: vrt2 = outsideParticle && vrt1 = insideParticle: + else if ( vrtRoot == vrt2 && is_insideParticle(aaPos[vrt1], 0) ) + {outsideCornerFound = get_intersection_point(intersectionPnt, vrt2, vrt1);} + // NO nearInterface handling necessary, since this is Pyramid or Tetrahedron case! + else if ( set_nearInterface(aaPos[vrt2], 0) || set_nearInterface(aaPos[vrt1], 0) ) + {UG_THROW("in 'CollectCorners_Prism3()': no nearInterface case possible!\n");} + else + continue; + + // check for correct inersectionPnt + if ( fabs(get_LSvalue_byPosition(intersectionPnt, 0)) > 1e-6 ) + UG_THROW("in 'CollectIBCorners3d_Prism3()': Error in computation of 'intersectionPnt':\n " + " intersectionPnt = " << intersectionPnt << "\n distance from interace = " << fabs(get_LSvalue_byPosition(intersectionPnt, 0)) << "\n"); + + } // end edge-loop + + if ( !outsideCornerFound ) + UG_THROW("During edge-loop no outsideCorner found!\n"); + + /////////////////////////////////////////////////////////////////// + // 3) push_back into 'vOutsideCorners' + if ( ! isIncluded(vOutsideCorners, intersectionPnt) ) + vOutsideCorners.push_back(intersectionPnt); + + } // end inside-case + else + // recall ousideIndex for 'm_vOriginalCornerID' + outsideInd = i; + + } // end vertex-loop + + for(size_t i = 0; i < 3; ++i) + { + m_vOriginalCornerID.push_back(outsideInd); + m_vInterfaceID.push_back(3+i); + } + +// WRITE 'vCornerCoords': FIRST insideCorners, SECOND outsideCorners + m_vCornerCoords.clear(); + for(size_t i = 0; i < 3; ++i) + m_vCornerCoords.push_back(vInsideCorners[i]); + for(size_t i = 0; i < 3; ++i) + m_vCornerCoords.push_back(vOutsideCorners[i]); + +// some checks: + if ( m_vInterfaceID.size() != 3 ) UG_THROW("wrong size for m_vInterfaceID! Should be 3 and is " << m_vInterfaceID.size() << "\n"); + if ( m_vOriginalCornerID.size()!= 6 ) UG_THROW("wrong size for m_vOriginalCornerID! Should be 6 and is " << m_vOriginalCornerID.size() << "\n"); + if ( vInsideCorners.size() != 3 ) UG_THROW("wrong size for vInsideCorners! Should be 3 and is " << vInsideCorners.size() << "\n"); + if ( vOutsideCorners.size() != 3 ) UG_THROW("wrong size for vOutsideCorners! Should be 3 and is " << vOutsideCorners.size() << "\n"); + if ( m_vCornerCoords.size()!= 6 ) UG_THROW("wrong size for m_vCornerCoords! Should be 6 and is " << m_vCornerCoords.size() << "\n"); + +// check 'vOutsideCorners'-array for CCW: +// get normal to triangle, built by 'vOutsideCorners'-array: + MathVector normal = vInsideCorners[0]; + VecSubtract(normal, vOutsideCorners[0], normal); + + if ( !isCCW(vOutsideCorners, normal) ) + { + m_vCornerCoords[4] = vOutsideCorners[2]; + m_vCornerCoords[5] = vOutsideCorners[1]; + } + +// check 'vInsideCorners'-array for CCW: + if ( !isCCW(vInsideCorners, normal) ) + { + m_vCornerCoords[1] = vInsideCorners[2]; + m_vCornerCoords[2] = vInsideCorners[1]; + } + + + return true; + +} + +template +bool CollectCorners_FlatTop_Prism4(GridObject* elem, + SmartPtr m_spMG, + typename domain_traits::position_accessor_type& aaPos, + std::vector >& m_vCornerCoords, + std::vector& m_vOriginalCornerID, + std::vector& m_vInterfaceID, + ReferenceObjectID& coarseROID) +{ +/////////////////////////////////////////////////////////////////// +// 1) push_back 'insideCorner' into 'm_vCornerCoords' +// 2) collect according outsideCorner (lying on the commom edge) +// 3) push_back 'intersectionPoints' into 'm_vCornerCoords' +// 4) check for CCW-property +/////////////////////////////////////////////////////////////////// + + bool output = false; + if ( output ) UG_LOG("_________________________ begin 'CollectCorners_FlatTop_Prism4()' ______________________________\n\n"); + + m_vCornerCoords.clear(); + m_vInterfaceID.clear(); + m_vOriginalCornerID.clear(); + +// collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *m_spMG, elem); + + // collect all edges of the element + std::vector vEdges; + CollectEdgesSorted(vEdges, *m_spMG, elem); + + // collect outside indices: + std::vector outsideInd; + for(size_t i = 0; i < vVertex.size(); ++i) + if ( is_insideParticle(aaPos[vVertex[i]], 0) ) + outsideInd.push_back(i); + + if ( outsideInd.size() != 2 ) UG_THROW("Wrong number of outsideInd!\n"); + for(size_t i = 0; i < outsideInd.size(); ++i) + if ( output ) UG_LOG("outsideInd = " << outsideInd[i] << "\n"); + + // loop vertices + for(size_t i = 0; i < vVertex.size(); ++i) + { + // get element + Vertex* vrtRoot = vVertex[i]; + + if ( ! is_insideParticle(aaPos[vrtRoot], 0) ) + { + /////////////////////////////////////////////////////////////////// + // 1) push_back 'insideCorner' into 'm_vCornerCoords' + m_vCornerCoords.push_back(aaPos[vrtRoot]); + m_vOriginalCornerID.push_back(i); + + /////////////////////////////////////////////////////////////////// + // 2) collect according outsideCorner (lying on the commom edge) + MathVector intersectionPnt; + for(size_t e = 0; e < vEdges.size(); ++e) + { + Edge* edge = vEdges[e]; + std::vector vVertexEdge; + CollectVertices(vVertexEdge, *m_spMG, edge); + if ( vVertexEdge.size() != 2 ) + UG_THROW("error in collecting vertices associated to an edge!\n"); + Vertex* vrt1 = vVertexEdge[0]; + Vertex* vrt2 = vVertexEdge[1]; + + // lies vrtRoot on a cutted edge? + // case1: vrt1 = outsideParticle && vrt2 = insideParticle: + if ( vrtRoot == vrt1 && is_insideParticle(aaPos[vrt2], 0) ) + { + /////////////////////////////////////////////////////////////////// + // 3) push_back 'intersectionPnt' into 'm_vCornerCoords' + get_intersection_point(intersectionPnt, vrt1, vrt2); + m_vCornerCoords.push_back(intersectionPnt); + + if ( vrt2 == vVertex[outsideInd[0]] ) + m_vOriginalCornerID.push_back(outsideInd[0]); + else if ( vrt2 == vVertex[outsideInd[1]] ) + m_vOriginalCornerID.push_back(outsideInd[1]); + else UG_THROW("No outsideInd found.\n"); + } + // case2: vrt1 = insideParticle && vrt2 = outsideParticle: + else if ( vrtRoot == vrt2 && is_insideParticle(aaPos[vrt1], 0) ) + { + /////////////////////////////////////////////////////////////////// + // 3) push_back 'intersectionPnt' into 'm_vCornerCoords' + get_intersection_point(intersectionPnt, vrt2, vrt1); + m_vCornerCoords.push_back(intersectionPnt); + + if ( vrt1 == vVertex[outsideInd[0]] ) + m_vOriginalCornerID.push_back(outsideInd[0]); + else if ( vrt1 == vVertex[outsideInd[1]] ) + m_vOriginalCornerID.push_back(outsideInd[1]); + else UG_THROW("No outsideInd found.\n"); + } + else + continue; + + // check for correct inersectionPnt + if ( fabs(get_LSvalue_byPosition(intersectionPnt, 0)) > 1e-6 ) + UG_THROW("in 'CollectIBCorners3d_Prism2()': Error in computation of 'intersectionPnt':\n " + " intersectionPnt = " << intersectionPnt << "\n distance from interace = " + << fabs(get_LSvalue_byPosition(intersectionPnt, 0)) << "\n"); + } // end edge-loop + } // end inside-case + } // end vertex-loop + + m_vInterfaceID.push_back(1); + m_vInterfaceID.push_back(2); + m_vInterfaceID.push_back(4); + m_vInterfaceID.push_back(5); + + +// some checks: + if ( m_vInterfaceID.size() != 4 ) UG_THROW("wrong size for m_vInterfaceID! Should be 4 and is " << m_vInterfaceID.size() << "\n"); + if ( m_vOriginalCornerID.size()!= 6 ) UG_THROW("wrong size for m_vOriginalCornerID! Should be 6 and is " << m_vOriginalCornerID.size() << "\n"); + if ( m_vCornerCoords.size()!= 6 ) UG_THROW("wrong size for m_vCornerCoords! Should be 6 and is " << m_vCornerCoords.size() << "\n"); + +/////////////////////////////////////////////////////////////////// +// 4) check for CCW-property + std::vector > vTriangleCorners1; + std::vector > vTriangleCorners2; + for(size_t i = 0; i < 3; ++i){ + vTriangleCorners1.push_back(m_vCornerCoords[i]); + vTriangleCorners2.push_back(m_vCornerCoords[3+i]); + } +// get normal to triangle, built by 'vOutsideCorners'-array: + MathVector normal = m_vCornerCoords[0]; + VecSubtract(normal, m_vCornerCoords[3], normal); + + if ( !isCCW(vTriangleCorners1, normal) ) + { + // switch ' m_vCornerCoords' + m_vCornerCoords[1] = vTriangleCorners1[2]; + m_vCornerCoords[2] = vTriangleCorners1[1]; + // switch ' m_vOriginalCornerID' + size_t buffer = m_vOriginalCornerID[1]; + m_vOriginalCornerID[1] = m_vOriginalCornerID[2]; + m_vOriginalCornerID[2] = buffer; + } + +// check 'vInsideCorners'-array for CCW: + if ( !isCCW(vTriangleCorners2, normal) ) + { + // switch ' m_vCornerCoords' + m_vCornerCoords[4] = vTriangleCorners2[2]; + m_vCornerCoords[5] = vTriangleCorners2[1]; + // switch ' m_vOriginalCornerID' + size_t buffer = m_vOriginalCornerID[4]; + m_vOriginalCornerID[4] = m_vOriginalCornerID[5]; + m_vOriginalCornerID[5] = buffer; + } + + + return true; + +} + +template +bool CollectCorners_FlatTop_Pyramid(GridObject* elem, + SmartPtr m_spMG, + typename domain_traits::position_accessor_type& aaPos, + std::vector >& m_vCornerCoords, + std::vector& m_vOriginalCornerID, + std::vector& m_vInterfaceID, + ReferenceObjectID& coarseROID) +{ +/////////////////////////////////////////////////////////////////// +// 1) push_back into 'vInsideCorners' +// 2) push_back into 'vOutsideCorners' the 2 outsideCorners on a cut edge +// 3) write nearInterfaceCorner on m_vCornerCoords[4], since in this setting it +// is ALWAYS the top of the Pyramid! --> see grid_object_3d.h for ordering! +/////////////////////////////////////////////////////////////////// + + bool output = false; + + if ( output ) UG_LOG("_________________________ begin 'CollectCorners_FlatTop_Pyramid()' ______________________________\n\n"); + + m_vCornerCoords.clear(); + m_vInterfaceID.clear(); + m_vOriginalCornerID.clear(); + +// buffer vectors for (cornerCoords, cornerIndex) - for application of 'ResortQuadrilateral'! + std::vector, size_t > > vOutsideCorners; + std::vector, size_t > > vInsideCorners; + std::pair, size_t > nearInterfaceData; + +// collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *m_spMG, elem); + + // collect all edges of the element + std::vector vEdges; + CollectEdgesSorted(vEdges, *m_spMG, elem); + + // loop vertices + size_t outsideInd; + for(size_t i = 0; i < vVertex.size(); ++i) + { + // get element + Vertex* vrtRoot = vVertex[i]; + + // get nearInterfaceData and directly write cornerCoords to data: + if ( set_nearInterface(aaPos[vrtRoot], 0) ) + nearInterfaceData = std::make_pair(aaPos[vrtRoot], i); + else if ( ! is_insideParticle(aaPos[vrtRoot], 0) ) + { + /////////////////////////////////////////////////////////////////// + // 1) push_back into 'vInsideCorners' + vInsideCorners.push_back(std::make_pair(aaPos[vrtRoot], i)); + m_vOriginalCornerID.push_back(i); + + /////////////////////////////////////////////////////////////////// + // 2) collect according outsideCorner (lying on the commom edge) + bool outsideCornerFound = false; + MathVector intersectionPnt; + for(size_t e = 0; e < vEdges.size(); ++e) + { + Edge* edge = vEdges[e]; + std::vector vVertexEdge; + CollectVertices(vVertexEdge, *m_spMG, edge); + if ( vVertexEdge.size() != 2 ) + UG_THROW("in 'NEWcall_Extrapolation': error in collecting vertices associated to an edge!....EXIT!...\n"); + Vertex* vrt1 = vVertexEdge[0]; + Vertex* vrt2 = vVertexEdge[1]; + + // lies vrtRoot on a cutted edge? + // do nothing for edges with 1 insideCorner and 1 nearInterface corner: + if ( set_nearInterface(aaPos[vrt1], 0) || set_nearInterface(aaPos[vrt2], 0) ) + continue; + // case2: vrt1 = outsideParticle && vrt2 = insideParticle: + else if ( vrtRoot == vrt1 && is_insideParticle(aaPos[vrt2], 0) ) + {outsideCornerFound = get_intersection_point(intersectionPnt, vrt1, vrt2);} + // case3: vrt2 = outsideParticle && vrt1 = insideParticle: + else if ( vrtRoot == vrt2 && is_insideParticle(aaPos[vrt1], 0) ) + {outsideCornerFound = get_intersection_point(intersectionPnt, vrt2, vrt1);} + else + continue; + + // check for correct inersectionPnt + if ( fabs(get_LSvalue_byPosition(intersectionPnt, 0)) > 1e-6 ) + UG_THROW("in 'CollectIBCorners3d_Prism3()': Error in computation of 'intersectionPnt':\n " + " intersectionPnt = " << intersectionPnt << "\n distance from interace = " << fabs(get_LSvalue_byPosition(intersectionPnt, 0)) << "\n"); + + } // end edge-loop + + if ( !outsideCornerFound ) + UG_THROW("During edge-loop no outsideCorner found!\n"); + + /////////////////////////////////////////////////////////////////// + // 3) push_back into 'vOutsideCorners' + vOutsideCorners.push_back(std::make_pair(intersectionPnt, 0)); + + } // end inside-case + else + // recall ousideIndex for 'm_vOriginalCornerID' + outsideInd = i; + + } // end vertex-loop + +// some checks: + if ( vInsideCorners.size() != 2 ) UG_THROW("wrong size for vInsideCorners! Should be 2 and is " << vInsideCorners.size() << "\n"); + if ( vOutsideCorners.size() != 2 ) UG_THROW("wrong size for vOutsideCorners! Should be 2 and is " << vOutsideCorners.size() << "\n"); + + for(size_t i = 0; i < vOutsideCorners.size(); ++i) + vOutsideCorners[i].second = outsideInd; + +// during ResortQuadrilateral: m_vCornerCoords.resize(4) and m_vOriginalCornerID.resize(4)! + MathVector normalDir; + VecSubtract(normalDir, nearInterfaceData.first, vOutsideCorners[0].first); + ResortQuadrilateral(vInsideCorners, vOutsideCorners, normalDir); + + m_vCornerCoords.push_back(nearInterfaceData.first); + m_vOriginalCornerID.push_back(nearInterfaceData.second); + m_vInterfaceID.push_back(4); + +// some checks: + if ( m_vInterfaceID.size() != 3 ) UG_THROW("wrong size for m_vInterfaceID! Should be 3 and is " << m_vInterfaceID.size() << "\n"); + if ( m_vOriginalCornerID.size()!= 5 ) UG_THROW("wrong size for m_vOriginalCornerID! Should be 5 and is " << m_vOriginalCornerID.size() << "\n"); + if ( m_vCornerCoords.size()!= 5 ) UG_THROW("wrong size for m_vCornerCoords! Should be 5 and is " << m_vCornerCoords.size() << "\n"); + + return true; + +} + +template +bool CollectCorners_FlatTop_originalTet(GridObject* elem, + SmartPtr m_spMG, + typename domain_traits::position_accessor_type& aaPos, + std::vector >& m_vCornerCoords, + std::vector& m_vOriginalCornerID, + std::vector& m_vInterfaceID, + ReferenceObjectID& coarseROID) +{ + if ( 0 ) UG_LOG("_________________________ begin 'CollectCorners_FlatTop_originalTet()' ______________________________\n\n"); + + ////////////////////////////////////////////// + // 1) fill vector with fluid corners: + ////////////////////////////////////////////// + + m_vCornerCoords.clear(); + m_vInterfaceID.clear(); + m_vOriginalCornerID.clear(); + +// collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *m_spMG, elem); + + // loop vertices + for(size_t i = 0; i < vVertex.size(); ++i) + { + // get element + Vertex* vrtRoot = vVertex[i]; + + if ( ! is_insideParticle(aaPos[vrtRoot], 0) ) + { + if ( set_nearInterface(aaPos[vrtRoot], 0) ) + { UG_THROW("NearInterface BUT !is_onInterfaceVertex() => error!\n"); } + else + { + m_vCornerCoords.push_back(aaPos[vrtRoot]); + m_vOriginalCornerID.push_back(i); + } + + } + else if ( set_nearInterface(aaPos[vrtRoot], 0) ) + { + m_vCornerCoords.push_back(aaPos[vrtRoot]); + m_vOriginalCornerID.push_back(i); + m_vInterfaceID.push_back(m_vCornerCoords.size()-1); + } + else + UG_THROW("in 'CollectCorners_FlatTop_originalTet()': outside fluid and NOT nearInterface case not possible!\n"); + } + + if ( 0 ) UG_LOG("_________________________ end 'CollectCorners_FlatTop_originalTet()' ______________________________\n\n"); + + return true; + +} + +template +int get_cutMode(std::vector vVertex, typename domain_traits::position_accessor_type& aaPos) +{ + size_t numOutside = 0; + size_t numNearInterface = 0; + for(size_t i = 0; i < vVertex.size(); ++i) + { + if ( is_insideParticle(aaPos[vVertex[i]], 0) ) + { + numOutside++; + if ( set_nearInterface(aaPos[vVertex[i]], 0) ) + numNearInterface++; + } + } + + bool logMode = false; + +// if all outside corners are nearInterface, no computation of intersectionPoints +// => purely collecting of corners necessary: + if ( numOutside == numNearInterface ) + { + if ( logMode ) UG_LOG("numOutside = " << numOutside << ", numNearInterface = " << numNearInterface << "\n"); + if ( logMode ) UG_LOG("cutMode = 0\n"); + return 0; // original + } + else if ( numOutside == 1 ) + { + if ( logMode ) UG_LOG("numOutside = " << numOutside << ", numNearInterface = " << numNearInterface << "\n"); + if ( logMode ) UG_LOG("cutMode = 1\n"); + return 1; // Prism3 + } + else if ( numOutside == 2 && numNearInterface == 0 ) + { + if ( logMode ) if ( logMode ) UG_LOG("numOutside = " << numOutside << ", numNearInterface = " << numNearInterface << "\n"); + if ( logMode ) UG_LOG("cutMode = 2\n"); + return 2; // Prism4 + } + else if ( numOutside == 2 && numNearInterface == 1 ) + { + if ( logMode ) UG_LOG("numOutside = " << numOutside << ", numNearInterface = " << numNearInterface << "\n"); + if ( logMode ) UG_LOG("cutMode = 3\n"); + return 3; // Pyramid + } + else if ( numOutside == 3 ) + { + if ( logMode ) UG_LOG("numOutside = " << numOutside << ", numNearInterface = " << numNearInterface << "\n"); + if ( logMode ) UG_LOG("cutMode = 4\n"); + return 4; // Tetrahedron + } + return -1; + +} + +template +bool CollectCorners_FlatTop_3d(GridObject* elem, + SmartPtr m_spMG, + typename domain_traits::position_accessor_type& aaPos, + std::vector >& m_vCornerCoords, + std::vector& m_vOriginalCornerID, + std::vector& m_vInterfaceID, + ReferenceObjectID& coarseROID) +{ + bool output = false; + if ( output ) UG_LOG("_________________________ begin 'get_LSvalue_byPosition()' ______________________________\n\n"); + + ////////////////////////////////////////////// + // 1) fill vector with fluid corners: + ////////////////////////////////////////////// + + m_vCornerCoords.clear(); + m_vInterfaceID.clear(); + m_vOriginalCornerID.clear(); + +// collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *m_spMG, elem); + +// remember boolian for check, weather there existe at least one vertex, which is FT! + bool isFTVertex = false; + for(size_t i = 0; i < vVertex.size(); ++i) + { + isFTVertex = is_insideParticle(aaPos[vVertex[i]], 0); + if ( isFTVertex ) + break; + } + if ( !isFTVertex ) + return false; + + + size_t cutMode = get_cutMode(vVertex, aaPos); + + switch(cutMode) + { + case 0: return CollectCorners_FlatTop_originalTet(elem,m_spMG,aaPos,m_vCornerCoords,m_vOriginalCornerID,m_vInterfaceID,coarseROID); + case 1: return CollectCorners_FlatTop_Prism3(elem,m_spMG,aaPos,m_vCornerCoords,m_vOriginalCornerID,m_vInterfaceID,coarseROID); + case 2: return CollectCorners_FlatTop_Prism4(elem,m_spMG,aaPos,m_vCornerCoords,m_vOriginalCornerID,m_vInterfaceID,coarseROID); + case 3: return CollectCorners_FlatTop_Pyramid(elem,m_spMG,aaPos,m_vCornerCoords,m_vOriginalCornerID,m_vInterfaceID,coarseROID); + case 4: return CollectCorners_FlatTop_2d(elem,m_spMG,aaPos,m_vCornerCoords,m_vOriginalCornerID,m_vInterfaceID,coarseROID); + default: { UG_LOG("cutMode = " << cutMode << "\n"); + throw(UGError("Error in calling case dependent CollectIBCorners3d()!")); + } + } + + +} + + +template +bool CollectCorners_StdFV(GridObject* elem, + SmartPtr m_spMG, + typename domain_traits::position_accessor_type& aaPos, + std::vector >& m_vCornerCoords, + std::vector& m_vOriginalCornerID, + std::vector& m_vInterfaceID, + ReferenceObjectID& coarseROID) +{ + ////////////////////////////////////////////// + // 1) fill vector with fluid corners: + ////////////////////////////////////////////// + + m_vCornerCoords.clear(); + m_vInterfaceID.clear(); + m_vOriginalCornerID.clear(); + +// buffer vectors for (cornerCoords, cornerIndex) + std::vector, size_t > > vOutsideCorners; + std::vector, size_t > > vInsideCorners; + std::vector, size_t > > vNearIntCorners; + +// collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *m_spMG, elem); + + // get prtIndex: + bool isOutsideVertex = false; + for(size_t i = 0; i < vVertex.size(); ++i) + { + // remember boolian for check, weather there existe at least one vertex, which is FT! + if ( is_insideParticle(vVertex[i], 0) ) + { + isOutsideVertex = true; + break; + } + } + + if ( !isOutsideVertex ) + return false; + +// loop vertices + for(size_t i = 0; i < vVertex.size(); ++i) + { + // get element + Vertex* vrtRoot = vVertex[i]; + + ////////////////////////////////////////////// + // case 1: + // vertex insideFluid => Position und index puschen + if ( !is_insideParticle(vVertex[i]) ) + { + if ( set_nearInterface(aaPos[vrtRoot], 0) ) + { + UG_THROW("NearInterface BUT !is_FT => neuerdings Fehler!!....\n"); + } + else + { + m_vCornerCoords.push_back(aaPos[vrtRoot]); + m_vOriginalCornerID.push_back(i); + + vInsideCorners.push_back(std::make_pair(aaPos[vrtRoot], i)); + } + + } + else + { + m_vCornerCoords.push_back(aaPos[vrtRoot]); + m_vOriginalCornerID.push_back(i); + m_vInterfaceID.push_back(m_vCornerCoords.size()-1); // attention: push AFTER 'm_vCornerCoords.push_back()'!! + + vOutsideCorners.push_back(std::make_pair(aaPos[vrtRoot], i)); + + } + + } + + // skip whole element, since only FT points are included + if ( dim == 2 && m_vCornerCoords.size() != 3 ) + UG_THROW("in 'CollectCorners_StdFV()': m_vCornerCoords.size() " + "= " << m_vCornerCoords.size() << "not possible!\n"); + if ( dim == 3 && m_vCornerCoords.size() != 4 ) + UG_THROW("in 'CollectCorners_StdFV()': m_vCornerCoords.size() " + "= " << m_vCornerCoords.size() << "not possible!\n"); + + + return true; +} + +} // end namespace ug + + +#endif /* INTEGRATE_TOOLS_H_ */ diff --git a/ugbase/lib_disc/lib_disc.h b/ugbase/lib_disc/lib_disc.h index 96a43eff6..e25557faf 100644 --- a/ugbase/lib_disc/lib_disc.h +++ b/ugbase/lib_disc/lib_disc.h @@ -108,6 +108,8 @@ #include "spatial_disc/disc_util/fe_geom.h" #include "spatial_disc/disc_util/fv1_geom.h" +#include "spatial_disc/disc_util/fv1FT_geom.h" +#include "spatial_disc/disc_util/fv1Cut_geom.h" #include "spatial_disc/disc_util/fvcr_geom.h" #include "spatial_disc/disc_util/fv_output.h" #include "spatial_disc/disc_util/fv_util.h" diff --git a/ugbase/lib_disc/operator/non_linear_operator/nl_gauss_seidel/nl_gauss_seidel.h b/ugbase/lib_disc/operator/non_linear_operator/nl_gauss_seidel/nl_gauss_seidel.h index 219bce9a5..fdb93e47d 100644 --- a/ugbase/lib_disc/operator/non_linear_operator/nl_gauss_seidel/nl_gauss_seidel.h +++ b/ugbase/lib_disc/operator/non_linear_operator/nl_gauss_seidel/nl_gauss_seidel.h @@ -68,12 +68,26 @@ class LocalToGlobalMapperNLGS : public ILocalToGlobalMapper void add_local_vec_to_global(vector_type& vec, const LocalVector& lvec, ConstSmartPtr dd); - /// adds a local matrix to the global matrix + /// sets certain entries to Dirichlet DoFs (in elem_disc_assembla_util) void add_local_mat_to_global(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd); - /// modifies local solution vector for adapted defect computation - void modify_LocalSol(LocalVector& vecMod, const LocalVector& lvec, ConstSmartPtr dd){} + void adjust_mat_global(matrix_type& mat, const LocalMatrix& lmat, + ConstSmartPtr dd){}; + + /// modifies local solution vector for adapted defect computation ( in elem_disc_assemble_util) + void modify_LocalData(LocalMatrix& locJ, LocalVector& locU, ConstSmartPtr dd){}; + void modify_LocalData(LocalVectorTimeSeries& uT, LocalMatrix& locJ, LocalVector& locU, ConstSmartPtr dd){}; + + void modify_LocalData(LocalVector& locD, LocalVector& tmpLocD, LocalVector& locU, ConstSmartPtr dd){}; + void modify_LocalData(LocalVectorTimeSeries& uT, LocalVector& locD, LocalVector& tmpLocD, LocalVector& locU, + ConstSmartPtr dd, size_t t){}; + + /// modifies global solution vector for adapted defect computation (in domain_disc_impl) + void modify_GlobalSol(vector_type& vecMod, const vector_type& vec, ConstSmartPtr dd){}; + + void modify_GlobalSol(SmartPtr > vSolMod, + ConstSmartPtr > vSol, ConstSmartPtr dd) {}; /// sets assembling index void set_assembling_index(const size_t assIndex){ m_assemblingIndex = assIndex;} diff --git a/ugbase/lib_disc/spatial_disc/ass_tuner.h b/ugbase/lib_disc/spatial_disc/ass_tuner.h index 5c952cf1d..01a06d537 100644 --- a/ugbase/lib_disc/spatial_disc/ass_tuner.h +++ b/ugbase/lib_disc/spatial_disc/ass_tuner.h @@ -37,6 +37,8 @@ #include "lib_grid/tools/selector_grid.h" #include "lib_disc/spatial_disc/local_to_global/local_to_global_mapper.h" #include "lib_disc/spatial_disc/elem_disc/elem_disc_interface.h" +#include "lib_disc/time_disc/solution_time_series.h" + namespace ug{ @@ -85,9 +87,23 @@ class LocalToGlobalMapper : public ILocalToGlobalMapper void add_local_mat_to_global(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd) { AddLocalMatrixToGlobal(mat,lmat);} - /// modifies local solution vector for adapted defect computation - void modify_LocalSol(LocalVector& vecMod, const LocalVector& lvec, ConstSmartPtr dd){}; - + /// sets certain entries to Dirichlet DoFs (in elem_disc_assembla_util) + void adjust_mat_global(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd){ } + + /// modifies local solution vector for adapted defect computation ( in elem_disc_assemble_util) + virtual void modify_LocalData(LocalMatrix& locJ, LocalVector& locU, ConstSmartPtr dd){}; + virtual void modify_LocalData(LocalVectorTimeSeries& uT, LocalMatrix& locJ, LocalVector& locU, ConstSmartPtr dd){}; + + virtual void modify_LocalData(LocalVector& locD, LocalVector& tmpLocD, LocalVector& locU, ConstSmartPtr dd){}; + virtual void modify_LocalData(LocalVectorTimeSeries& uT, LocalVector& locD, LocalVector& tmpLocD, LocalVector& locU, + ConstSmartPtr dd, size_t t){}; + + /// modifies global solution vector for adapted defect computation (in domain_disc_impl) + void modify_GlobalSol(vector_type& vecMod, const vector_type& vec, ConstSmartPtr dd){}; + + void modify_GlobalSol(SmartPtr > vSolMod, + ConstSmartPtr > vSol, ConstSmartPtr dd) {}; + /// destructor ~LocalToGlobalMapper() {}; }; @@ -141,9 +157,37 @@ class AssemblingTuner ConstSmartPtr dd) const { m_pMapper->add_local_mat_to_global(mat, lmat, dd);} - void modify_LocalSol(LocalVector& vecMod, const LocalVector& lvec, + /// sets certain entries to Dirichlet DoFs (in elem_disc_assembla_util) + void adjust_mat_global(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd) const - { m_pMapper->modify_LocalSol(vecMod, lvec, dd);} + { m_pMapper->adjust_mat_global(mat, lmat, dd);} + + /// modifies local solution vector for adapted defect computation ( in elem_disc_assemble_util) + void modify_LocalData(LocalVector& locD, LocalVector& tmpLocD, LocalVector& locU, + ConstSmartPtr dd) const + { m_pMapper->modify_LocalData(locD, tmpLocD, locU, dd);} + void modify_LocalData(LocalVectorTimeSeries& uT, LocalVector& locD, LocalVector& tmpLocD, LocalVector& locU, + ConstSmartPtr dd, size_t t) const + { m_pMapper->modify_LocalData(uT, locD, tmpLocD, locU, dd, t);} + + void modify_LocalData(LocalMatrix& locJ, LocalVector& locU, + ConstSmartPtr dd) const + { m_pMapper->modify_LocalData(locJ, locU, dd);} + void modify_LocalData(LocalVectorTimeSeries& uT, LocalMatrix& locJ, LocalVector& locU, + ConstSmartPtr dd) const + { m_pMapper->modify_LocalData(uT, locJ, locU, dd);} + + /// modifies global solution vector for adapted defect computation (in domain_disc_impl) + void modify_GlobalSol(vector_type& vecMod, const vector_type& vec, + ConstSmartPtr dd) const + { m_pMapper->modify_GlobalSol(vecMod, vec, dd);} + void modify_GlobalSol(SmartPtr > vSolMod, + ConstSmartPtr > vSol, + ConstSmartPtr dd) const + { m_pMapper->modify_GlobalSol(vSolMod, vSol, dd);} + + + /// sets a marker to exclude elements from assembling /** * This methods sets a marker. Only elements that are marked will be diff --git a/ugbase/lib_disc/spatial_disc/disc_util/fv1Cut_geom.cpp b/ugbase/lib_disc/spatial_disc/disc_util/fv1Cut_geom.cpp new file mode 100644 index 000000000..3e34fbd79 --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/disc_util/fv1Cut_geom.cpp @@ -0,0 +1,1859 @@ +/* + * Copyright (c) 2010-2015: G-CSC, Goethe University Frankfurt + * Author: Andreas Vogel + * + * This file is part of UG4. + * + * UG4 is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License version 3 (as published by the + * Free Software Foundation) with the following additional attribution + * requirements (according to LGPL/GPL v3 §7): + * + * (1) The following notice must be displayed in the Appropriate Legal Notices + * of covered and combined works: "Based on UG4 (www.ug4.org/license)". + * + * (2) The following notice must be displayed at a prominent place in the + * terminal output of covered works: "Based on UG4 (www.ug4.org/license)". + * + * (3) The following bibliography is recommended for citation and must be + * preserved in all covered files: + * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively + * parallel geometric multigrid solver on hierarchically distributed grids. + * Computing and visualization in science 16, 4 (2013), 151-164" + * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel + * flexible software system for simulating pde based models on high performance + * computers. Computing and visualization in science 16, 4 (2013), 165-179" + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +#ifndef __H__UG__LIB_DISC__SPATIAL_DISC__DISC_HELPER__FV1Cut_GEOMETRY_IMPL_ +#define __H__UG__LIB_DISC__SPATIAL_DISC__DISC_HELPER__FV1Cut_GEOMETRY_IMPL_ + +#include "common/util/provider.h" +#include "fv1Cut_geom.h" +#include "lib_disc/reference_element/reference_element.h" +#include "lib_disc/quadrature/quadrature.h" +#include "lib_algebra/common/operations_vec.h" + +#include "lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/interface_handler_diffusion.h" + + +namespace ug{ + +/** + * \tparam dim dimension of coordinates + * \tparam TRefElem Reference element type + * \tparam maxMid Maximum number of elements for all dimensions + */ +template +static void ComputeMidPoints(const TRefElem& rRefElem, + const MathVector vCorner[], + MathVector vvMid[][maxMid]) +{ +// compute local midpoints for all geometric objects with 0 < d <= dim + for(int d = 1; d <= dim; ++d) + { + // loop geometric objects of dimension d + for(size_t i = 0; i < rRefElem.num(d); ++i) + { + // set first node + const size_t coID0 = rRefElem.id(d, i, 0, 0); + vvMid[d][i] = vCorner[coID0]; + + // add corner coordinates of the corners of the geometric object + for(size_t j = 1; j < rRefElem.num(d, i, 0); ++j) + { + const size_t coID = rRefElem.id(d, i, 0, j); + vvMid[d][i] += vCorner[coID]; + } + + // scale for correct averaging + vvMid[d][i] *= 1./(rRefElem.num(d, i, 0)); + } + } + +// for OCTAHEDRONS: add midpoints of imaginary faces, edges and volumes +// resulting from the division into 4 tetrahedra alongside inner edge 3->1 + if (rRefElem.roid() == ROID_OCTAHEDRON) + { + // diagonal 3->1, diagonal 1->3 + VecScaleAdd(vvMid[1][rRefElem.num(1)], 0.5, vCorner[3], 0.5, vCorner[1]); + VecScaleAdd(vvMid[1][rRefElem.num(1)+1], 0.5, vCorner[1], 0.5, vCorner[3]); + + // subface 1,2,3; subface 1,3,2; subface 1,3,4; subface 1,4,3; face 1,3,5; face 1,5,3; face 1,0,3; face 1,3,0 + vvMid[2][rRefElem.num(2)] = vCorner[1]; + vvMid[2][rRefElem.num(2)] += vCorner[2]; + vvMid[2][rRefElem.num(2)] += vCorner[3]; + vvMid[2][rRefElem.num(2)] *= 1.0/3.0; + + vvMid[2][rRefElem.num(2)+1] = vCorner[1]; + vvMid[2][rRefElem.num(2)+1] += vCorner[3]; + vvMid[2][rRefElem.num(2)+1] += vCorner[2]; + vvMid[2][rRefElem.num(2)+1] *= 1.0/3.0; + + vvMid[2][rRefElem.num(2)+2] = vCorner[1]; + vvMid[2][rRefElem.num(2)+2] += vCorner[3]; + vvMid[2][rRefElem.num(2)+2] += vCorner[4]; + vvMid[2][rRefElem.num(2)+2] *= 1.0/3.0; + + vvMid[2][rRefElem.num(2)+3] = vCorner[1]; + vvMid[2][rRefElem.num(2)+3] += vCorner[4]; + vvMid[2][rRefElem.num(2)+3] += vCorner[3]; + vvMid[2][rRefElem.num(2)+3] *= 1.0/3.0; + + vvMid[2][rRefElem.num(2)+4] = vCorner[1]; + vvMid[2][rRefElem.num(2)+4] += vCorner[3]; + vvMid[2][rRefElem.num(2)+4] += vCorner[5]; + vvMid[2][rRefElem.num(2)+4] *= 1.0/3.0; + + vvMid[2][rRefElem.num(2)+5] = vCorner[1]; + vvMid[2][rRefElem.num(2)+5] += vCorner[5]; + vvMid[2][rRefElem.num(2)+5] += vCorner[3]; + vvMid[2][rRefElem.num(2)+5] *= 1.0/3.0; + + vvMid[2][rRefElem.num(2)+6] = vCorner[1]; + vvMid[2][rRefElem.num(2)+6] += vCorner[0]; + vvMid[2][rRefElem.num(2)+6] += vCorner[3]; + vvMid[2][rRefElem.num(2)+6] *= 1.0/3.0; + + vvMid[2][rRefElem.num(2)+7] = vCorner[1]; + vvMid[2][rRefElem.num(2)+7] += vCorner[3]; + vvMid[2][rRefElem.num(2)+7] += vCorner[0]; + vvMid[2][rRefElem.num(2)+7] *= 1.0/3.0; + + // subvolume 1,2,3,5; subvolume 1,3,4,5; subvolume 1,2,3,0; subvolume 1,3,4,0 + vvMid[3][rRefElem.num(3)] = vCorner[1]; + vvMid[3][rRefElem.num(3)] += vCorner[2]; + vvMid[3][rRefElem.num(3)] += vCorner[3]; + vvMid[3][rRefElem.num(3)] += vCorner[5]; + vvMid[3][rRefElem.num(3)] *= 0.25; + + vvMid[3][rRefElem.num(3)+1] = vCorner[1]; + vvMid[3][rRefElem.num(3)+1] += vCorner[3]; + vvMid[3][rRefElem.num(3)+1] += vCorner[4]; + vvMid[3][rRefElem.num(3)+1] += vCorner[5]; + vvMid[3][rRefElem.num(3)+1] *= 0.25; + + vvMid[3][rRefElem.num(3)+2] = vCorner[1]; + vvMid[3][rRefElem.num(3)+2] += vCorner[2]; + vvMid[3][rRefElem.num(3)+2] += vCorner[3]; + vvMid[3][rRefElem.num(3)+2] += vCorner[0]; + vvMid[3][rRefElem.num(3)+2] *= 0.25; + + vvMid[3][rRefElem.num(3)+3] = vCorner[1]; + vvMid[3][rRefElem.num(3)+3] += vCorner[3]; + vvMid[3][rRefElem.num(3)+3] += vCorner[4]; + vvMid[3][rRefElem.num(3)+3] += vCorner[0]; + vvMid[3][rRefElem.num(3)+3] *= 0.25; + } +} + +/** + * \param[in] i indicates that scvf corresponds to i'th edge of ref elem + */ +template +static void ComputeSCVFMidID(const TRefElem& rRefElem, + MidID vMidID[], int i) +{ + static const int dim = TRefElem::dim; + + if (rRefElem.roid() != ROID_PYRAMID && rRefElem.roid() != ROID_OCTAHEDRON) + { + // set mid ids + { + // start at edge midpoint + vMidID[0] = MidID(1,i); + + // loop up dimension + if(dim == 2) + { + vMidID[1] = MidID(dim, 0); // center of element + } + else if (dim == 3) + { + vMidID[1] = MidID(2, rRefElem.id(1, i, 2, 0)); // side 0 + vMidID[2] = MidID(dim, 0); // center of element + vMidID[3] = MidID(2, rRefElem.id(1, i, 2, 1)); // side 1 + } + } + } +// pyramid here + else if(rRefElem.roid() == ROID_PYRAMID) + { + // start at edge midpoint + vMidID[0] = MidID(1,i/2); + + // there are 2 scvf per edge + if(i%2 == 0){ + vMidID[1] = MidID(2, rRefElem.id(1, i/2, 2, 0)); // side 0 + vMidID[2] = MidID(dim, 0); // center of element + } else { + vMidID[1] = MidID(dim, 0); // center of element + vMidID[2] = MidID(2, rRefElem.id(1, i/2, 2, 1)); // side 1 + } + } +// octahedron here (analogue to scvf ordering in pyramids but in top/bottom pairs) + else if(rRefElem.roid() == ROID_OCTAHEDRON) + { + switch (i) + { + // scvf of edge 4 (top) + case 0: vMidID[0] = MidID(1,4); // edge 4 + vMidID[1] = MidID(2,8); // subface 0 = 1,2,3 + vMidID[2] = MidID(3,1); // subvolume 0 + vMidID[3] = MidID(2,4); // face 4 + break; + // scvf of edge 4 (bottom) + case 1: vMidID[0] = MidID(1,4); // edge 4 + vMidID[1] = MidID(2,9); // subface 1 = 1,3,2 + vMidID[2] = MidID(3,3); // subvolume 2 + vMidID[3] = MidID(2,0); // face 0 + break; + + + // scvf of edge 5 (top) + case 2: vMidID[0] = MidID(1,5); // edge 5 + vMidID[1] = MidID(2,8); // subface 0 = 1,2,3 + vMidID[2] = MidID(3,1); // subvolume 0 + vMidID[3] = MidID(2,5); // face 5 + break; + // scvf of edge 5 (bottom) + case 3: vMidID[0] = MidID(1,5); // edge 5 + vMidID[1] = MidID(2,9); // subface 1 = 1,3,2 + vMidID[2] = MidID(3,3); // subvolume 2 + vMidID[3] = MidID(2,1); // face 1 + break; + + + // scvf of diagonal 3->1 (top) in subvolume 0 + case 4: vMidID[0] = MidID(1,12);// diagonal 3->1 + vMidID[1] = MidID(2,8); // subface 0 = 1,2,3 + vMidID[2] = MidID(3,1); // subvolume 0 + vMidID[3] = MidID(2,13);// face 1,5,3 + break; + // scvf of diagonal 1->3 (bottom) in subvolume 2 + case 5: vMidID[0] = MidID(1,13);// diagonal 1->3 + vMidID[1] = MidID(2,9); // subface 1 = 1,3,2 + vMidID[2] = MidID(3,3); // subvolume 2 + vMidID[3] = MidID(2,14);// face 1,0,3 + break; + + + // scvf of edge 8 in subvolume 0 + case 6: vMidID[0] = MidID(1,8); // edge 8 + vMidID[1] = MidID(2,4); // face 4 + vMidID[2] = MidID(3,1); // subvolume 0 + vMidID[3] = MidID(2,13);// face 1,5,3 + break; + // scvf of edge 0 in subvolume 2 + case 7: vMidID[0] = MidID(1,0); // edge 0 + vMidID[1] = MidID(2,15);// face 1,3,0 + vMidID[2] = MidID(3,3); // subvolume 2 + vMidID[3] = MidID(2,0); // face 0 + break; + + + // scvf of edge 9 + case 8: vMidID[0] = MidID(1,9); // edge 9 + vMidID[1] = MidID(2,5); // face 5 + vMidID[2] = MidID(3,1); // subvolume 0 + vMidID[3] = MidID(2,4); // face 4 + break; + // scvf of edge 1 + case 9: vMidID[0] = MidID(1,1); // edge 1 + vMidID[1] = MidID(2,0); // face 0 + vMidID[2] = MidID(3,3); // subvolume 2 + vMidID[3] = MidID(2,1); // face 1 + break; + + + // scvf of edge 10 in subvolume 0 + case 10:vMidID[0] = MidID(1,10);// edge 10 + vMidID[1] = MidID(2,12);// face 1,3,5 + vMidID[2] = MidID(3,1); // subvolume 0 + vMidID[3] = MidID(2,5); // face 5 + break; + // scvf of edge 2 in subvolume 2 + case 11:vMidID[0] = MidID(1,2); // edge 2 + vMidID[1] = MidID(2,1); // face 1 + vMidID[2] = MidID(3,3); // subvolume 2 + vMidID[3] = MidID(2,14);// face 1,0,3 + break; + + + // scvf of diagonal 1->3 (top) in subvolume 1 + case 12:vMidID[0] = MidID(1,13);// diagonal 1->3 + vMidID[1] = MidID(2,10);// subface 2 = 1,3,4 + vMidID[2] = MidID(3,2); // subvolume 1 + vMidID[3] = MidID(2,12);// face 1,3,5 + break; + // scvf of diagonal 3->1 (bottom) in subvolume 3 + case 13:vMidID[0] = MidID(1,12);// diagonal 3->1 + vMidID[1] = MidID(2,11);// subface 3 = 1,4,3 + vMidID[2] = MidID(3,4); // subvolume 3 + vMidID[3] = MidID(2,15);// face 1,3,0 + break; + + + // scvf of edge 6 (top) + case 14:vMidID[0] = MidID(1,6); // edge 6 + vMidID[1] = MidID(2,10);// subface 2 = 1,3,4 + vMidID[2] = MidID(3,2); // subvolume 1 + vMidID[3] = MidID(2,6); // face 6 + break; + // scvf of edge 6 (bottom) + case 15:vMidID[0] = MidID(1,6); // edge 6 + vMidID[1] = MidID(2,11);// subface 3 = 1,4,3 + vMidID[2] = MidID(3,4); // subvolume 3 + vMidID[3] = MidID(2,2); // face 2 + break; + + + // scvf of edge 7 (top) + case 16:vMidID[0] = MidID(1,7); // edge 7 + vMidID[1] = MidID(2,10);// subface 2 = 1,3,4 + vMidID[2] = MidID(3,2); // subvolume 1 + vMidID[3] = MidID(2,7); // face 7 + break; + // scvf of edge 7 (bottom) + case 17:vMidID[0] = MidID(1,7); // edge 7 + vMidID[1] = MidID(2,11);// subface 3 = 1,4,3 + vMidID[2] = MidID(3,4); // subvolume 3 + vMidID[3] = MidID(2,3); // face 3 + break; + + + // scvf of edge 8 in subvolume 1 + case 18:vMidID[0] = MidID(1,8); // edge 8 + vMidID[1] = MidID(2,13);// face 1,5,3 + vMidID[2] = MidID(3,2); // subvolume 1 + vMidID[3] = MidID(2,7); // face 7 + break; + // scvf of edge 0 in subvolume 3 + case 19:vMidID[0] = MidID(1,0); // edge 0 + vMidID[1] = MidID(2,3); // face 3 + vMidID[2] = MidID(3,4); // subvolume 3 + vMidID[3] = MidID(2,15);// face 1,3,0 + break; + + + // scvf of edge 10 in subvolume 1 + case 20:vMidID[0] = MidID(1,10);// edge 10 + vMidID[1] = MidID(2,6); // face 6 + vMidID[2] = MidID(3,2); // subvolume 1 + vMidID[3] = MidID(2,12);// face 1,3,5 + break; + // scvf of edge 2 in subvolume 3 + case 21:vMidID[0] = MidID(1,2); // edge 2 + vMidID[1] = MidID(2,14);// face 1,0,3 + vMidID[2] = MidID(3,4); // subvolume 3 + vMidID[3] = MidID(2,2); // face 2 + break; + + + // scvf of edge 11 in subvolume 1 + case 22:vMidID[0] = MidID(1,11);// edge 11 + vMidID[1] = MidID(2,7); // face 7 + vMidID[2] = MidID(3,2); // subvolume 1 + vMidID[3] = MidID(2,6); // face 6 + break; + // scvf of edge 3 in subvolume 3 + case 23:vMidID[0] = MidID(1,3); // edge 3 + vMidID[1] = MidID(2,2); // face 2 + vMidID[2] = MidID(3,4); // subvolume 3 + vMidID[3] = MidID(2,3); // face 3 + break; + + + default:UG_THROW("Octahedron only has 24 SCVFs (no. 0-23), but requested no. " << i << "."); + break; + } + } +} + +/** + * \param[in] i indicates that scv corresponds to i'th corner of ref elem + */ +template +static void ComputeSCVMidID(const TRefElem& rRefElem, + MidID vMidID[], int i) +{ + static const int dim = TRefElem::dim; + + if (rRefElem.roid() != ROID_PYRAMID && rRefElem.roid() != ROID_OCTAHEDRON) + { + if(dim == 1) + { + vMidID[0] = MidID(0, i); // set node as corner of scv + vMidID[1] = MidID(dim, 0); // center of element + } + else if(dim == 2) + { + vMidID[0] = MidID(0, i); // set node as corner of scv + vMidID[1] = MidID(1, rRefElem.id(0, i, 1, 0)); // edge 1 + vMidID[2] = MidID(dim, 0); // center of element + vMidID[3] = MidID(1, rRefElem.id(0, i, 1, 1)); // edge 2 + } + else if(dim == 3) + { + vMidID[0] = MidID(0, i); // set node as corner of scv + vMidID[1] = MidID(1, rRefElem.id(0, i, 1, 1)); // edge 1 + vMidID[2] = MidID(2, rRefElem.id(0, i, 2, 0)); // face 0 + vMidID[3] = MidID(1, rRefElem.id(0, i, 1, 0)); // edge 0 + vMidID[4] = MidID(1, rRefElem.id(0, i, 1, 2)); // edge 2 + vMidID[5] = MidID(2, rRefElem.id(0, i, 2, 2)); // face 2 + vMidID[6] = MidID(dim, 0); // center of element + vMidID[7] = MidID(2, rRefElem.id(0, i, 2, 1)); // face 1 + } + else {UG_THROW("Dimension higher than 3 not implemented.");} + } +// pyramid here + else if (rRefElem.roid() == ROID_PYRAMID) + { + // start at edge midpoint + vMidID[3] = MidID(1,i/4); + + // there are 2 scvf per edge + if(i%4 == 0 || i%4 == 1){ + vMidID[1] = MidID(2, rRefElem.id(1, i/4, 2, 0)); // side 0 + vMidID[2] = MidID(dim, 0); // center of element + } else { + vMidID[1] = MidID(dim, 0); // center of element + vMidID[2] = MidID(2, rRefElem.id(1, i/4, 2, 1)); // side 1 + } + + // connect to from / to corners of edge + if(i%2 == 0){ + vMidID[0] = MidID(0, rRefElem.id(1, i/4, 0, 0)); // from + } else { + vMidID[0] = MidID(0, rRefElem.id(1, i/4, 0, 1)); // to + } + } + // octahedron here (analogue to scv ordering in pyramids but in top/bottom pairs) + else if(rRefElem.roid() == ROID_OCTAHEDRON) + { + switch (i) + { + // scv of corner 1 in subvolume 0 (top) + case 0: vMidID[0] = MidID(0,1); // corner 1 + vMidID[1] = MidID(1,4); // edge 4 + vMidID[2] = MidID(2,8); // subface 0 = 1,2,3 + vMidID[3] = MidID(1,12);// edge 3->1 + vMidID[4] = MidID(1,8); // edge 8 + vMidID[5] = MidID(2,4); // face 4 + vMidID[6] = MidID(3,1); // subvolume 0 + vMidID[7] = MidID(2,13);// face 1,5,3 + break; + // scv of corner 1 in subvolume 2 (bottom) + case 1: vMidID[0] = MidID(0,1); // corner 1 + vMidID[1] = MidID(1,13);// edge 1->3 + vMidID[2] = MidID(2,9); // subface 1 = 1,3,2 + vMidID[3] = MidID(1,4); // edge 4 + vMidID[4] = MidID(1,0); // edge 0 + vMidID[5] = MidID(2,15);// face 1,3,0 + vMidID[6] = MidID(3,3); // subvolume 2 + vMidID[7] = MidID(2,0); // face 0 + break; + + + // scv of corner 2 in subvolume 0 (top) + case 2: vMidID[0] = MidID(0,2); // corner 2 + vMidID[1] = MidID(1,5); // edge 5 + vMidID[2] = MidID(2,8); // subface 0 = 1,2,3 + vMidID[3] = MidID(1,4); // edge 4 + vMidID[4] = MidID(1,9); // edge 9 + vMidID[5] = MidID(2,5); // face 5 + vMidID[6] = MidID(3,1); // subvolume 0 + vMidID[7] = MidID(2,4); // face 4 + break; + // scv of corner 2 in subvolume 2 (bottom) + case 3: vMidID[0] = MidID(0,2); // corner 2 + vMidID[1] = MidID(1,4); // edge 4 + vMidID[2] = MidID(2,9); // subface 1 = 1,3,2 + vMidID[3] = MidID(1,5); // edge 5 + vMidID[4] = MidID(1,1); // edge 1 + vMidID[5] = MidID(2,0); // face 0 + vMidID[6] = MidID(3,3); // subvolume 2 + vMidID[7] = MidID(2,1); // face 1 + break; + + + // scv of corner 3 in subvolume 0 (top) + case 4: vMidID[0] = MidID(0,3); // corner 3 + vMidID[1] = MidID(1,12);// edge 3->1 + vMidID[2] = MidID(2,8); // subface 0 = 1,2,3 + vMidID[3] = MidID(1,5); // edge 5 + vMidID[4] = MidID(1,10);// edge 10 + vMidID[5] = MidID(2,13);// face 1,5,3 + vMidID[6] = MidID(3,1); // subvolume 0 + vMidID[7] = MidID(2,5); // face 5 + break; + // scv of corner 3 in subvolume 2 (bottom) + case 5: vMidID[0] = MidID(0,3); // corner 3 + vMidID[1] = MidID(1,5); // edge 5 + vMidID[2] = MidID(2,9); // subface 0 = 1,3,2 + vMidID[3] = MidID(1,13);// edge 1->3 + vMidID[4] = MidID(1,2); // edge 2 + vMidID[5] = MidID(2,1); // face 1 + vMidID[6] = MidID(3,3); // subvolume 2 + vMidID[7] = MidID(2,15);// face 1,3,0 + break; + + + // scv of corner 5 in subvolume 0 (top) + case 6: vMidID[0] = MidID(0,5); // corner 5 + vMidID[1] = MidID(1,9); // edge 9 + vMidID[2] = MidID(2,4); // face 4 + vMidID[3] = MidID(1,8); // edge 8 + vMidID[4] = MidID(1,10);// edge 10 + vMidID[5] = MidID(2,5); // face 5 + vMidID[6] = MidID(3,1); // subvolume 0 + vMidID[7] = MidID(2,13);// subface 1,5,3 + break; + // scv of corner 0 in subvolume 2 (bottom) + case 7: vMidID[0] = MidID(0,0); // corner 0 + vMidID[1] = MidID(1,0); // edge 0 + vMidID[2] = MidID(2,0); // face 0 + vMidID[3] = MidID(1,1); // edge 1 + vMidID[4] = MidID(1,2); // edge 2 + vMidID[5] = MidID(2,14);// subface 1,0,3 + vMidID[6] = MidID(3,3); // subvolume 2 + vMidID[7] = MidID(2,1); // face 1 + break; + + + // scv of corner 1 in subvolume 1 (top) + case 8: vMidID[0] = MidID(0,1); // corner 1 + vMidID[1] = MidID(1,13);// edge 1->3 + vMidID[2] = MidID(2,10);// subface 2 = 1,3,4 + vMidID[3] = MidID(1,7); // edge 7 + vMidID[4] = MidID(1,8); // edge 8 + vMidID[5] = MidID(2,12);// face 1,3,5 + vMidID[6] = MidID(3,2); // subvolume 1 + vMidID[7] = MidID(2,7); // face 7 + break; + // scv of corner 1 in subvolume 3 (bottom) + case 9: vMidID[0] = MidID(0,1); // corner 1 + vMidID[1] = MidID(1,7); // edge 7 + vMidID[2] = MidID(2,11);// subface 3 = 1,4,3 + vMidID[3] = MidID(1,12);// edge 3->1 + vMidID[4] = MidID(1,0); // edge 0 + vMidID[5] = MidID(2,3); // face 3 + vMidID[6] = MidID(3,4); // subvolume 3 + vMidID[7] = MidID(2,14);// face 1,0,3 + break; + + + // scv of corner 3 in subvolume 1 (top) + case 10:vMidID[0] = MidID(0,3); // corner 3 + vMidID[1] = MidID(1,6); // edge 6 + vMidID[2] = MidID(2,10);// subface 2 = 1,3,4 + vMidID[3] = MidID(1,13);// edge 1->3 + vMidID[4] = MidID(1,10);// edge 10 + vMidID[5] = MidID(2,6); // face 6 + vMidID[6] = MidID(3,2); // subvolume 1 + vMidID[7] = MidID(2,12);// face 1,3,5 + break; + // scv of corner 3 in subvolume 3 (bottom) + case 11:vMidID[0] = MidID(0,3); // corner 3 + vMidID[1] = MidID(1,12);// edge 3->1 + vMidID[2] = MidID(2,11);// subface 3 = 1,4,3 + vMidID[3] = MidID(1,6); // edge 6 + vMidID[4] = MidID(1,2); // edge 2 + vMidID[5] = MidID(2,14);// face 1,0,3 + vMidID[6] = MidID(3,4); // subvolume 3 + vMidID[7] = MidID(2,2); // face 2 + break; + + + // scv of corner 4 in subvolume 1 (top) + case 12:vMidID[0] = MidID(0,4); // corner 4 + vMidID[1] = MidID(1,7); // edge 7 + vMidID[2] = MidID(2,10);// subface 2 = 1,3,4 + vMidID[3] = MidID(1,6); // edge 6 + vMidID[4] = MidID(1,11);// edge 11 + vMidID[5] = MidID(2,7); // face 7 + vMidID[6] = MidID(3,2); // subvolume 1 + vMidID[7] = MidID(2,6); // face 6 + break; + // scv of corner 4 in subvolume 3 (bottom) + case 13:vMidID[0] = MidID(0,4); // corner 4 + vMidID[1] = MidID(1,6); // edge 6 + vMidID[2] = MidID(2,11);// subface 3 = 1,4,3 + vMidID[3] = MidID(1,7); // edge 7 + vMidID[4] = MidID(1,3); // edge 3 + vMidID[5] = MidID(2,2); // face 2 + vMidID[6] = MidID(3,4); // subvolume 3 + vMidID[7] = MidID(2,3); // face 3 + break; + + + // scv of corner 5 in subvolume 1 (top) + case 14:vMidID[0] = MidID(0,5); // corner 5 + vMidID[1] = MidID(1,10);// edge 10 + vMidID[2] = MidID(2,12);// subface 1,3,5 + vMidID[3] = MidID(1,8); // edge 8 + vMidID[4] = MidID(1,11);// edge 11 + vMidID[5] = MidID(2,6); // face 6 + vMidID[6] = MidID(3,2); // subvolume 1 + vMidID[7] = MidID(2,7); // face 7 + break; + // scv of corner 0 in subvolume 3 (bottom) + case 15:vMidID[0] = MidID(0,0); // corner 0 + vMidID[1] = MidID(1,0); // edge 0 + vMidID[2] = MidID(2,15);// subface 1,3,0 + vMidID[3] = MidID(1,2); // edge 2 + vMidID[4] = MidID(1,3); // edge 3 + vMidID[5] = MidID(2,3); // face 3 + vMidID[6] = MidID(3,4); // subvolume 3 + vMidID[7] = MidID(2,2); // face 2 + break; + default:UG_THROW("Octahedron only has 16 SCVs (no. 0-15), but requested no. " << i << "."); + break; + } + } +} + +/** + * \param[in] i indicates that bf corresponds to i'th corner of ref elem + */ +template +static void ComputeBFMidID(const TRefElem& rRefElem, int side, + MidID vMidID[], int co) +{ + static const int dim = TRefElem::dim; + + // number of corners of side + const int coOfSide = rRefElem.num(dim-1, side, 0); + + // set mid ids + if (dim == 1) + { + vMidID[0] = MidID(0, rRefElem.id(0, side, 0, co)); + } + else if(dim == 2) + { + vMidID[co%2] = MidID(0, rRefElem.id(1, side, 0, co)); // corner of side + vMidID[(co+1)%2] = MidID(1, side); // side midpoint + } + else if (dim == 3) + { + vMidID[0] = MidID(0, rRefElem.id(2, side, 0, co)); // corner of side + vMidID[1] = MidID(1, rRefElem.id(2, side, 1, co)); // edge co + vMidID[2] = MidID(2, side); // side midpoint + vMidID[3] = MidID(1, rRefElem.id(2, side, 1, (co -1 + coOfSide)%coOfSide)); // edge co-1 + } +} + +template +static void CopyCornerByMidID(MathVector vCorner[], + const MidID vMidID[], + MathVector vvMidPos[][maxMid], + const size_t numCo) +{ + for(size_t i = 0; i < numCo; ++i) + { + const size_t d = vMidID[i].dim; + const size_t id = vMidID[i].id; + vCorner[i] = vvMidPos[d][id]; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// FV1FT Geometry for Reference Element Type +//////////////////////////////////////////////////////////////////////////////// + +template +FV1CutGeometry:: +FV1CutGeometry() + : m_pElem(NULL), m_rRefElem(Provider::get()), + m_rTrialSpace(Provider::get()) +{ + update_local_data(); +} + +template +void FV1CutGeometry:: +update_local_data() +{ + +// set corners of element as local centers of nodes + for(size_t i = 0; i < m_rRefElem.num(0); ++i) + m_vvLocMid[0][i] = m_rRefElem.corner(i); + +// compute local midpoints + ComputeMidPoints(m_rRefElem, m_vvLocMid[0], m_vvLocMid); + +// set up local information for SubControlVolumeFaces (scvf) + for(size_t i = 0; i < num_scvf(); ++i) + { + + // this scvf separates the given nodes + if (m_rRefElem.REFERENCE_OBJECT_ID != ROID_PYRAMID && m_rRefElem.REFERENCE_OBJECT_ID != ROID_OCTAHEDRON) + { + m_vSCVF[i].From = m_rRefElem.id(1, i, 0, 0); + m_vSCVF[i].To = m_rRefElem.id(1, i, 0, 1); + } + // special case pyramid + else if(m_rRefElem.REFERENCE_OBJECT_ID == ROID_PYRAMID) + { + // map according to order defined in ComputeSCVFMidID + m_vSCVF[i].From = m_rRefElem.id(1, i/2, 0, 0); + m_vSCVF[i].To = m_rRefElem.id(1, i/2, 0, 1); + } + // special case octahedron (scvf not mappable by edges) + else if(m_rRefElem.REFERENCE_OBJECT_ID == ROID_OCTAHEDRON) + { + // map according to order defined in ComputeSCVFMidID + switch(i) + { + case 0: m_vSCVF[i].From = 1; + m_vSCVF[i].To = 2; + break; + case 1: m_vSCVF[i].From = 2; + m_vSCVF[i].To = 1; + break; + + + case 2: m_vSCVF[i].From = 2; + m_vSCVF[i].To = 3; + break; + case 3: m_vSCVF[i].From = 3; + m_vSCVF[i].To = 2; + break; + + + case 4: m_vSCVF[i].From = 3; + m_vSCVF[i].To = 1; + break; + case 5: m_vSCVF[i].From = 1; + m_vSCVF[i].To = 3; + break; + + + case 6: m_vSCVF[i].From = 1; + m_vSCVF[i].To = 5; + break; + case 7: m_vSCVF[i].From = 1; + m_vSCVF[i].To = 0; + break; + + + case 8: m_vSCVF[i].From = 2; + m_vSCVF[i].To = 5; + break; + case 9: m_vSCVF[i].From = 2; + m_vSCVF[i].To = 0; + break; + + + case 10:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 5; + break; + case 11:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 0; + break; + + + case 12:m_vSCVF[i].From = 1; + m_vSCVF[i].To = 3; + break; + case 13:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 1; + break; + + + case 14:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 4; + break; + case 15:m_vSCVF[i].From = 4; + m_vSCVF[i].To = 3; + break; + + + case 16:m_vSCVF[i].From = 4; + m_vSCVF[i].To = 1; + break; + case 17:m_vSCVF[i].From = 1; + m_vSCVF[i].To = 4; + break; + + + case 18:m_vSCVF[i].From = 1; + m_vSCVF[i].To = 5; + break; + case 19:m_vSCVF[i].From = 1; + m_vSCVF[i].To = 0; + break; + + + case 20:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 5; + break; + case 21:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 0; + break; + + + case 22:m_vSCVF[i].From = 4; + m_vSCVF[i].To = 5; + break; + case 23:m_vSCVF[i].From = 4; + m_vSCVF[i].To = 0; + break; + } + } + + // compute mid ids of the scvf + ComputeSCVFMidID(m_rRefElem, m_vSCVF[i].vMidID, i); + + // copy local corners of scvf + CopyCornerByMidID(m_vSCVF[i].vLocPos, m_vSCVF[i].vMidID, m_vvLocMid, SCVF::numCo); + + // integration point + AveragePositions(m_vSCVF[i].localIP, m_vSCVF[i].vLocPos, SCVF::numCo); + } + +// set up local informations for SubControlVolumes (scv) +// each scv is associated to one corner of the element + for(size_t i = 0; i < num_scv(); ++i) + { + // store associated node + if (m_rRefElem.REFERENCE_OBJECT_ID != ROID_PYRAMID && m_rRefElem.REFERENCE_OBJECT_ID != ROID_OCTAHEDRON) + { + m_vSCV[i].nodeId = i; + } + // special case pyramid + else if(m_rRefElem.REFERENCE_OBJECT_ID == ROID_PYRAMID) + { + // map according to order defined in ComputeSCVMidID + if(i%2 == 0){ + m_vSCV[i].nodeId = m_rRefElem.id(1, i/4, 0, 0); // from + } else { + m_vSCV[i].nodeId = m_rRefElem.id(1, i/4, 0, 1); // to + } + } + // special case octahedron (scvf not mappable by edges) + else if(m_rRefElem.REFERENCE_OBJECT_ID == ROID_OCTAHEDRON) + { + // map according to order defined in ComputeSCVMidID + switch(i) + { + case 0: m_vSCV[i].nodeId = 1; + break; + case 1: m_vSCV[i].nodeId = 1; + break; + + + case 2: m_vSCV[i].nodeId = 2; + break; + case 3: m_vSCV[i].nodeId = 2; + break; + + + case 4: m_vSCV[i].nodeId = 3; + break; + case 5: m_vSCV[i].nodeId = 3; + break; + + + case 6: m_vSCV[i].nodeId = 5; + break; + case 7: m_vSCV[i].nodeId = 0; + break; + + + case 8: m_vSCV[i].nodeId = 1; + break; + case 9: m_vSCV[i].nodeId = 1; + break; + + + case 10:m_vSCV[i].nodeId = 3; + break; + case 11:m_vSCV[i].nodeId = 3; + break; + + + case 12:m_vSCV[i].nodeId = 4; + break; + case 13:m_vSCV[i].nodeId = 4; + break; + + + case 14:m_vSCV[i].nodeId = 5; + break; + case 15:m_vSCV[i].nodeId = 0; + break; + } + } + + // compute mid ids scv + ComputeSCVMidID(m_rRefElem, m_vSCV[i].midId, i); + + // copy local corners of scv + CopyCornerByMidID(m_vSCV[i].vLocPos, m_vSCV[i].midId, m_vvLocMid, m_vSCV[i].num_corners()); + } + +// compute Shapes and Derivatives + for(size_t i = 0; i < num_scvf(); ++i) + { + m_rTrialSpace.shapes(&(m_vSCVF[i].vShape[0]), m_vSCVF[i].local_ip()); + m_rTrialSpace.grads(&(m_vSCVF[i].vLocalGrad[0]), m_vSCVF[i].local_ip()); + } + + for(size_t i = 0; i < num_scv(); ++i) + { + m_rTrialSpace.shapes(&(m_vSCV[i].vShape[0]), m_vSCV[i].local_ip()); + m_rTrialSpace.grads(&(m_vSCV[i].vLocalGrad[0]), m_vSCV[i].local_ip()); + } + +// copy ip positions in a list for Sub Control Volumes Faces (SCVF) + for(size_t i = 0; i < num_scvf(); ++i) + m_vLocSCVF_IP[i] = scvf(i).local_ip(); + + if(ref_elem_type::REFERENCE_OBJECT_ID == ROID_PYRAMID || ref_elem_type::REFERENCE_OBJECT_ID == ROID_OCTAHEDRON) + for(size_t i = 0; i < num_scv(); ++i) + m_vLocSCV_IP[i] = scv(i).local_ip(); +} + +/// update data for given element +template +void FV1CutGeometry:: +update(GridObject* elem, const MathVector* vCornerCoords, const ISubsetHandler* ish) +{ + UG_ASSERT(dynamic_cast(elem) != NULL, "Wrong element type."); + TElem* pElem = static_cast(elem); + +// if already update for this element, do nothing + if(m_pElem == pElem) return; else m_pElem = pElem; + +// remember global position of nodes + for(size_t i = 0; i < m_rRefElem.num(0); ++i) + m_vvGloMid[0][i] = vCornerCoords[i]; + +// compute global midpoints + ComputeMidPoints(m_rRefElem, m_vvGloMid[0], m_vvGloMid); + + +// compute global informations for scvf + for(size_t i = 0; i < num_scvf(); ++i) + { + // copy local corners of scvf + CopyCornerByMidID(m_vSCVF[i].vGloPos, m_vSCVF[i].vMidID, m_vvGloMid, SCVF::numCo); + + // integration point + AveragePositions(m_vSCVF[i].globalIP, m_vSCVF[i].vGloPos, SCVF::numCo); + + // normal on scvf + traits::NormalOnSCVF(m_vSCVF[i].Normal, m_vSCVF[i].vGloPos, m_vvGloMid[0]); + } + +// compute size of scv + for(size_t i = 0; i < num_scv(); ++i) + { + // copy global corners + CopyCornerByMidID(m_vSCV[i].vGloPos, m_vSCV[i].midId, m_vvGloMid, m_vSCV[i].num_corners()); + + // compute volume of scv + m_vSCV[i].Vol = ElementSize(m_vSCV[i].vGloPos); + + /* + * Only for debug purposes testing octahedral FV1 discretization + * + MathVector baryCenter(0.0); + for(size_t j = 0; j < 8; ++j) + { + baryCenter += m_vSCV[i].vLocPos[j]; + } + + baryCenter *= 1.0/8.0; + * + */ + + } + +// Shapes and Derivatives + m_mapping.update(vCornerCoords); + +// if mapping is linear, compute jacobian only once and copy + if(ReferenceMapping::isLinear) + { + MathMatrix JtInv; + m_mapping.jacobian_transposed_inverse(JtInv, m_vSCVF[0].local_ip()); + const number detJ = m_mapping.sqrt_gram_det(m_vSCVF[0].local_ip()); + + for(size_t i = 0; i < num_scvf(); ++i) + { + m_vSCVF[i].JtInv = JtInv; + m_vSCVF[i].detj = detJ; + } + + for(size_t i = 0; i < num_scv(); ++i) + { + m_vSCV[i].JtInv = JtInv; + m_vSCV[i].detj = detJ; + } + } +// else compute jacobian for each integration point + else + { + for(size_t i = 0; i < num_scvf(); ++i) + { + m_mapping.jacobian_transposed_inverse(m_vSCVF[i].JtInv, m_vSCVF[i].local_ip()); + m_vSCVF[i].detj = m_mapping.sqrt_gram_det(m_vSCVF[i].local_ip()); + } + for(size_t i = 0; i < num_scv(); ++i) + { + m_mapping.jacobian_transposed_inverse(m_vSCV[i].JtInv, m_vSCV[i].local_ip()); + m_vSCV[i].detj = m_mapping.sqrt_gram_det(m_vSCV[i].local_ip()); + } + } + +// compute global gradients + for(size_t i = 0; i < num_scvf(); ++i) + for(size_t sh = 0 ; sh < scvf(i).num_sh(); ++sh) + MatVecMult(m_vSCVF[i].vGlobalGrad[sh], m_vSCVF[i].JtInv, m_vSCVF[i].vLocalGrad[sh]); + + for(size_t i = 0; i < num_scv(); ++i) + for(size_t sh = 0 ; sh < scv(i).num_sh(); ++sh) + MatVecMult(m_vSCV[i].vGlobalGrad[sh], m_vSCV[i].JtInv, m_vSCV[i].vLocalGrad[sh]); + +// Copy ip pos in list for SCVF + for(size_t i = 0; i < num_scvf(); ++i) + m_vGlobSCVF_IP[i] = scvf(i).global_ip(); + + if(ref_elem_type::REFERENCE_OBJECT_ID == ROID_PYRAMID || ref_elem_type::REFERENCE_OBJECT_ID == ROID_OCTAHEDRON) + for(size_t i = 0; i < num_scv(); ++i) + m_vGlobSCV_IP[i] = scv(i).global_ip(); + +// if no boundary subsets required, return + if(num_boundary_subsets() == 0 || ish == NULL) return; + else update_boundary_faces(pElem, vCornerCoords, ish); +} + +template +void FV1CutGeometry:: +update_boundary_faces(GridObject* elem, const MathVector* vCornerCoords, const ISubsetHandler* ish) +{ + UG_ASSERT(dynamic_cast(elem) != NULL, "Wrong element type."); + TElem* pElem = static_cast(elem); + +// get grid + Grid& grid = *(ish->grid()); + +// vector of subset indices of side + std::vector vSubsetIndex; + +// get subset indices for sides (i.e. edge in 2d, faces in 3d) + if(dim == 1) { + std::vector vVertex; + CollectVertices(vVertex, grid, pElem); + vSubsetIndex.resize(vVertex.size()); + for(size_t i = 0; i < vVertex.size(); ++i) + vSubsetIndex[i] = ish->get_subset_index(vVertex[i]); + } + if(dim == 2) { + std::vector vEdges; + CollectEdgesSorted(vEdges, grid, pElem); + vSubsetIndex.resize(vEdges.size()); + for(size_t i = 0; i < vEdges.size(); ++i) + vSubsetIndex[i] = ish->get_subset_index(vEdges[i]); + } + if(dim == 3) { + std::vector vFaces; + CollectFacesSorted(vFaces, grid, pElem); + vSubsetIndex.resize(vFaces.size()); + for(size_t i = 0; i < vFaces.size(); ++i) + vSubsetIndex[i] = ish->get_subset_index(vFaces[i]); + } + +// loop requested subset + typename std::map >::iterator it; + for (it=m_mapVectorBF.begin() ; it != m_mapVectorBF.end(); ++it) + { + // get subset index + const int bndIndex = (*it).first; + + // get vector of BF for element + std::vector& vBF = (*it).second; + + // clear vector + vBF.clear(); + + // current number of bf + size_t curr_bf = 0; + + // loop sides of element + for(size_t side = 0; side < vSubsetIndex.size(); ++side) + { + // skip non boundary sides + if(vSubsetIndex[side] != bndIndex) continue; + + // number of corners of side + const int coOfSide = m_rRefElem.num(dim-1, side, 0); + + // resize vector + vBF.resize(curr_bf + coOfSide); + + // loop corners + for(int co = 0; co < coOfSide; ++co) + { + // get current bf + BF& bf = vBF[curr_bf]; + + // set node id == scv this bf belongs to + bf.nodeId = m_rRefElem.id(dim-1, side, 0, co); + + // Compute MidID for BF + ComputeBFMidID(m_rRefElem, side, bf.vMidID, co); + + // copy corners of bf + CopyCornerByMidID(bf.vLocPos, bf.vMidID, m_vvLocMid, BF::numCo); + CopyCornerByMidID(bf.vGloPos, bf.vMidID, m_vvGloMid, BF::numCo); + + // integration point + AveragePositions(bf.localIP, bf.vLocPos, BF::numCo); + AveragePositions(bf.globalIP, bf.vGloPos, BF::numCo); + + // normal on scvf + traits::NormalOnBF(bf.Normal, bf.vGloPos, m_vvGloMid[0]); + + // compute volume + bf.Vol = VecTwoNorm(bf.Normal); + + m_rTrialSpace.shapes(&(bf.vShape[0]), bf.localIP); + m_rTrialSpace.grads(&(bf.vLocalGrad[0]), bf.localIP); + + m_mapping.jacobian_transposed_inverse(bf.JtInv, bf.localIP); + bf.detj = m_mapping.sqrt_gram_det(bf.localIP); + + for(size_t sh = 0 ; sh < bf.num_sh(); ++sh) + MatVecMult(bf.vGlobalGrad[sh], bf.JtInv, bf.vLocalGrad[sh]); + + // increase curr_bf + ++curr_bf; + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Dim-dependent Finite Volume Geometry +//////////////////////////////////////////////////////////////////////////////// +template +void DimFV1CutGeometry:: +update_local(ReferenceObjectID roid) +{ + m_roid = roid; + +// get reference element + try + { + const DimReferenceElement& rRefElem + = ReferenceElementProvider::get(m_roid); + + // set corners of element as local centers of nodes + for(size_t i = 0; i < rRefElem.num(0); ++i) + m_vvLocMid[0][i] = rRefElem.corner(i); + + // compute local midpoints + ComputeMidPoints, maxMid> + (rRefElem, m_vvLocMid[0], m_vvLocMid); + + // set number of scvf / scv of this roid + if(m_roid != ROID_PYRAMID && m_roid != ROID_OCTAHEDRON) + { + m_numSCV = rRefElem.num(0); + m_numSCVF = rRefElem.num(1); + } + else if(dim == 3 && m_roid == ROID_PYRAMID) + { + UG_WARNING("Pyramid Finite Volume Geometry for 1st order currently " + "implemented in DimFV1Geom EXPERIMENTATLLY. Please contact " + "Martin Stepniewski or Andreas Vogel if you see this message.") + + m_numSCV = 4*rRefElem.num(1); + m_numSCVF = 2*rRefElem.num(1); + } + else if(dim == 3 && m_roid == ROID_OCTAHEDRON) + { + // Case octahedron + m_numSCV = 16; + m_numSCVF = 24; + } + + // set up local informations for SubControlVolumeFaces (scvf) + // each scvf is associated to one edge of the element + for(size_t i = 0; i < num_scvf(); ++i) + { + // this scvf separates the given nodes + if (m_roid != ROID_PYRAMID && m_roid != ROID_OCTAHEDRON) + { + m_vSCVF[i].From = rRefElem.id(1, i, 0, 0); + m_vSCVF[i].To = rRefElem.id(1, i, 0, 1); + } + // special case pyramid (scvf not mappable by edges) + else if (dim == 3 && m_roid == ROID_PYRAMID) + { + // map according to order defined in ComputeSCVFMidID + m_vSCVF[i].From = rRefElem.id(1, i/2, 0, 0); + m_vSCVF[i].To = rRefElem.id(1, i/2, 0, 1); + } + // special case octahedron (scvf not mappable by edges) + else if(dim == 3 && m_roid == ROID_OCTAHEDRON) + { + // map according to order defined in ComputeSCVFMidID + switch(i) + { + case 0: m_vSCVF[i].From = 1; + m_vSCVF[i].To = 2; + break; + case 1: m_vSCVF[i].From = 2; + m_vSCVF[i].To = 1; + break; + + + case 2: m_vSCVF[i].From = 2; + m_vSCVF[i].To = 3; + break; + case 3: m_vSCVF[i].From = 3; + m_vSCVF[i].To = 2; + break; + + + case 4: m_vSCVF[i].From = 3; + m_vSCVF[i].To = 1; + break; + case 5: m_vSCVF[i].From = 1; + m_vSCVF[i].To = 3; + break; + + + case 6: m_vSCVF[i].From = 1; + m_vSCVF[i].To = 5; + break; + case 7: m_vSCVF[i].From = 1; + m_vSCVF[i].To = 0; + break; + + + case 8: m_vSCVF[i].From = 2; + m_vSCVF[i].To = 5; + break; + case 9: m_vSCVF[i].From = 2; + m_vSCVF[i].To = 0; + break; + + + case 10:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 5; + break; + case 11:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 0; + break; + + + case 12:m_vSCVF[i].From = 1; + m_vSCVF[i].To = 3; + break; + case 13:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 1; + break; + + + case 14:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 4; + break; + case 15:m_vSCVF[i].From = 4; + m_vSCVF[i].To = 3; + break; + + + case 16:m_vSCVF[i].From = 4; + m_vSCVF[i].To = 1; + break; + case 17:m_vSCVF[i].From = 1; + m_vSCVF[i].To = 4; + break; + + + case 18:m_vSCVF[i].From = 1; + m_vSCVF[i].To = 5; + break; + case 19:m_vSCVF[i].From = 1; + m_vSCVF[i].To = 0; + break; + + + case 20:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 5; + break; + case 21:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 0; + break; + + + case 22:m_vSCVF[i].From = 4; + m_vSCVF[i].To = 5; + break; + case 23:m_vSCVF[i].From = 4; + m_vSCVF[i].To = 0; + break; + } + } + + + // compute mid ids of the scvf + ComputeSCVFMidID(rRefElem, m_vSCVF[i].vMidID, i); + + // copy local corners of scvf + CopyCornerByMidID(m_vSCVF[i].vLocPos, m_vSCVF[i].vMidID, m_vvLocMid, SCVF::numCo); + + // integration point + AveragePositions(m_vSCVF[i].localIP, m_vSCVF[i].vLocPos, SCVF::numCo); + } + + // set up local informations for SubControlVolumes (scv) + // each scv is associated to one corner of the element + for(size_t i = 0; i < num_scv(); ++i) + { + // store associated node + if (m_roid != ROID_PYRAMID && m_roid != ROID_OCTAHEDRON) + { + m_vSCV[i].nodeId = i; + } + // special case pyramid (scv not mappable by corners) + else if(dim == 3 && m_roid == ROID_PYRAMID) + { + // map according to order defined in ComputeSCVMidID + if(i%2 == 0){ + m_vSCV[i].nodeId = rRefElem.id(1, i/4, 0, 0); // from + } else { + m_vSCV[i].nodeId = rRefElem.id(1, i/4, 0, 1); // to + } + } + // special case octahedron (scvf not mappable by edges) + else if(dim == 3 && m_roid == ROID_OCTAHEDRON) + { + // map according to order defined in ComputeSCVMidID + switch(i) + { + case 0: m_vSCV[i].nodeId = 1; + break; + case 1: m_vSCV[i].nodeId = 1; + break; + + + case 2: m_vSCV[i].nodeId = 2; + break; + case 3: m_vSCV[i].nodeId = 2; + break; + + + case 4: m_vSCV[i].nodeId = 3; + break; + case 5: m_vSCV[i].nodeId = 3; + break; + + + case 6: m_vSCV[i].nodeId = 5; + break; + case 7: m_vSCV[i].nodeId = 0; + break; + + + case 8: m_vSCV[i].nodeId = 1; + break; + case 9: m_vSCV[i].nodeId = 1; + break; + + + case 10:m_vSCV[i].nodeId = 3; + break; + case 11:m_vSCV[i].nodeId = 3; + break; + + + case 12:m_vSCV[i].nodeId = 4; + break; + case 13:m_vSCV[i].nodeId = 4; + break; + + + case 14:m_vSCV[i].nodeId = 5; + break; + case 15:m_vSCV[i].nodeId = 0; + break; + } + } + + // compute mid ids scv + ComputeSCVMidID(rRefElem, m_vSCV[i].vMidID, i); + + // copy local corners of scv + CopyCornerByMidID(m_vSCV[i].vLocPos, m_vSCV[i].vMidID, m_vvLocMid, m_vSCV[i].num_corners()); + } + + ///////////////////////// + // Shapes and Derivatives + ///////////////////////// + + const LocalShapeFunctionSet& TrialSpace = + LocalFiniteElementProvider::get(m_roid, LFEID(LFEID::LAGRANGE, dim, 1)); + + m_nsh = TrialSpace.num_sh(); + + for(size_t i = 0; i < num_scvf(); ++i) + { + m_vSCVF[i].numSH = TrialSpace.num_sh(); + TrialSpace.shapes(&(m_vSCVF[i].vShape[0]), m_vSCVF[i].localIP); + TrialSpace.grads(&(m_vSCVF[i].vLocalGrad[0]), m_vSCVF[i].localIP); + } + + for(size_t i = 0; i < num_scv(); ++i) + { + m_vSCV[i].numSH = TrialSpace.num_sh(); + TrialSpace.shapes(&(m_vSCV[i].vShape[0]), m_vSCV[i].vLocPos[0]); + TrialSpace.grads(&(m_vSCV[i].vLocalGrad[0]), m_vSCV[i].vLocPos[0]); + } + + } + UG_CATCH_THROW("DimFV1CutGeometry: update failed."); + +// copy ip positions in a list for Sub Control Volumes Faces (SCVF) + for(size_t i = 0; i < num_scvf(); ++i) + m_vLocSCVF_IP[i] = scvf(i).local_ip(); + + if(roid == ROID_PYRAMID || roid == ROID_OCTAHEDRON) + for(size_t i = 0; i < num_scv(); ++i) + m_vLocSCV_IP[i] = scv(i).local_ip(); +} + + +/// update data for given element +template +void DimFV1CutGeometry:: +update(GridObject* pElem, const MathVector* vCornerCoords, const ISubsetHandler* ish) +{ +/////////////////////////////////////////////////////////////////////////////////// +// (1) - (4) Pre-processing for re-computing the cooridnates of element +// corners 'vCornerCoords' in case of a cut element + + set_element_modus(false); + + m_spInterfaceHandler->clear_boundary_faces(); + +// (1) collect potentially new 'vCornerCoords' and set the elemModus +// (INSIDE_DOM/OUTSIDE_DOM/CUT_BY_INTERFACE) + bool do_update_local = false; + try{ + do_update_local = m_spInterfaceHandler->update_elem(pElem, vCornerCoords); + } + UG_CATCH_THROW("DimFV1CutGeometry: access to InterfaceHander::update_elem() failed!."); + +// (2) If OUTSIDE_DOM: set m_roid to usual value and perform local update + if( m_spInterfaceHandler->elementModus() == OUTSIDE_DOM) + { + if ( dim == 2 ) m_roid = ROID_TRIANGLE; + if ( dim == 3 ) m_roid = ROID_TETRAHEDRON; + + update_local(m_roid); + } + +// (3) get computed roid and perform the local update based on that + if (do_update_local || m_roid != m_spInterfaceHandler->roid() ) + { + if( m_spInterfaceHandler->elementModus() != OUTSIDE_DOM ) + { + m_roid = m_spInterfaceHandler->roid(); + update_local(m_roid); + } + } + +// (4) set needed flag + if(m_spInterfaceHandler->elementModus() == CUT_BY_INTERFACE) + set_element_modus(true); + + +////////////////////////////////////////////////////////////////////////////////////// +// NOW: perform usual computations on potentially updated cut element 'vCornerCoords' + +// get reference element + try{ + const DimReferenceElement& rRefElem + = ReferenceElementProvider::get(m_roid); + +// remember global position of nodes + for(size_t i = 0; i < rRefElem.num(0); ++i) + m_vvGloMid[0][i] = m_spInterfaceHandler->corner(i); + + +// compute local midpoints + ComputeMidPoints, maxMid>(rRefElem, m_vvGloMid[0], m_vvGloMid); + +// compute global informations for scvf + for(size_t i = 0; i < num_scvf(); ++i) + { + // copy local corners of scvf + CopyCornerByMidID(m_vSCVF[i].vGloPos, m_vSCVF[i].vMidID, m_vvGloMid, SCVF::numCo); + + // integration point + AveragePositions(m_vSCVF[i].globalIP, m_vSCVF[i].vGloPos, SCVF::numCo); + + // normal on scvf + traits::NormalOnSCVF(m_vSCVF[i].Normal, m_vSCVF[i].vGloPos, m_vvGloMid[0]); + } + +// compute size of scv + for(size_t i = 0; i < num_scv(); ++i) + { + // copy global corners + CopyCornerByMidID(m_vSCV[i].vGloPos, m_vSCV[i].vMidID, m_vvGloMid, m_vSCV[i].num_corners()); + + // compute volume of scv + m_vSCV[i].Vol = ElementSize(m_vSCV[i].vGloPos); + } + +// get reference mapping + DimReferenceMapping& rMapping = ReferenceMappingProvider::get(m_roid); + rMapping.update(m_spInterfaceHandler->corners()); + //rMapping.update(vCornerCoords); + + + //\todo compute with on virt. call +// compute jacobian for linear mapping + if(rMapping.is_linear()) + { + MathMatrix JtInv; + rMapping.jacobian_transposed_inverse(JtInv, m_vSCVF[0].local_ip()); + const number detJ = rMapping.sqrt_gram_det(m_vSCVF[0].local_ip()); + + for(size_t i = 0; i < num_scvf(); ++i) + { + m_vSCVF[i].JtInv = JtInv; + m_vSCVF[i].detj = detJ; + } + + for(size_t i = 0; i < num_scv(); ++i) + { + m_vSCV[i].JtInv = JtInv; + m_vSCV[i].detj = detJ; + } + } +// else compute jacobian for each integration point + else + { + for(size_t i = 0; i < num_scvf(); ++i) + { + rMapping.jacobian_transposed_inverse(m_vSCVF[i].JtInv, m_vSCVF[i].local_ip()); + m_vSCVF[i].detj = rMapping.sqrt_gram_det(m_vSCVF[i].local_ip()); + } + for(size_t i = 0; i < num_scv(); ++i) + { + rMapping.jacobian_transposed_inverse(m_vSCV[i].JtInv, m_vSCV[i].local_ip()); + m_vSCV[i].detj = rMapping.sqrt_gram_det(m_vSCV[i].local_ip()); + } + } + +// compute global gradients + for(size_t i = 0; i < num_scvf(); ++i) + for(size_t sh = 0; sh < scvf(i).num_sh(); ++sh) + MatVecMult(m_vSCVF[i].vGlobalGrad[sh], m_vSCVF[i].JtInv, m_vSCVF[i].vLocalGrad[sh]); + + for(size_t i = 0; i < num_scv(); ++i) + for(size_t sh = 0; sh < scv(i).num_sh(); ++sh) + MatVecMult(m_vSCV[i].vGlobalGrad[sh], m_vSCV[i].JtInv, m_vSCV[i].vLocalGrad[sh]); + +// copy ip points in list (SCVF) + for(size_t i = 0; i < num_scvf(); ++i) + m_vGlobSCVF_IP[i] = scvf(i).global_ip(); + + if(m_roid == ROID_PYRAMID || m_roid == ROID_OCTAHEDRON) + for(size_t i = 0; i < num_scv(); ++i) + m_vGlobSCV_IP[i] = scv(i).global_ip(); + + } + UG_CATCH_THROW("DimFV1CutGeometry: update failed."); + + +///////////////////////////////////////////////////////////////////////////// +// compute boundary faces of inner boundary: m_vBF-data +// --> needed for assembling boundary-conditions on immersed interface + if(m_spInterfaceHandler->elementModus() == CUT_BY_INTERFACE) + { + update_inner_boundary_faces(); + m_spInterfaceHandler->update_inner_boundary(vCornerCoords); + } + + +// if no boundary subsets required, return + if(num_boundary_subsets() == 0 || ish == NULL) return; + else update_boundary_faces(pElem, vCornerCoords, ish); +} + + + +// compare implementation of 'DimFV1Geometry::update_boundary_faces()' +template +void DimFV1CutGeometry:: +update_inner_boundary_faces() +{ + ///////////////////////////////////////////////////////////////////////////// + // get general data + ///////////////////////////////////////////////////////////////////////////// + try{ + const DimReferenceElement& rRefElem + = ReferenceElementProvider::get(m_roid); + + DimReferenceMapping& rMapping = ReferenceMappingProvider::get(m_roid); + rMapping.update(m_spInterfaceHandler->corners()); + + const LocalShapeFunctionSet& TrialSpace = + LocalFiniteElementProvider::get(m_roid, LFEID(LFEID::LAGRANGE, dim, 1)); + + ///////////////////////////////////////////////////////////////////////////// + // collect boudary faces + ///////////////////////////////////////////////////////////////////////////// + + // get number of sides of element + size_t numSides = 0; + numSides = rRefElem.num(dim-1); + + // current number of bf + size_t curr_bf = 0; + + std::vector& vBF = m_spInterfaceHandler->get_boundary_faces(); + + vBF.clear(); + + // loop sides of element + for(size_t side = 0; side < numSides; ++side) + { + // side is no boundary face => continue + if ( !m_spInterfaceHandler->is_boundary_face(side) ) + continue; + + // number of corners of side (special case bottom side pyramid) + const int coOfSide = (m_roid != ROID_PYRAMID || side != 0) + ? rRefElem.num(dim-1, side, 0) : rRefElem.num(dim-1, side, 0) + 2; + + // resize vector + vBF.resize(curr_bf + coOfSide); + + // loop corners + for(int co = 0; co < coOfSide; ++co) + { + // get current bf + BF& bf = vBF[curr_bf]; + + // set node id == scv this bf belongs to + if (m_roid != ROID_PYRAMID || side != 0){ + bf.nodeId = rRefElem.id(dim-1, side, 0, co); + } + else + { + // map according to order defined in ComputeBFMidID + bf.nodeId = rRefElem.id(dim-1, side, 0, (co % 3) + (co>3 ? 1 : 0)); + } + + // Compute MidID for BF + ComputeBFMidID(rRefElem, side, bf.vMidID, co); + + // copy corners of bf + CopyCornerByMidID(bf.vLocPos, bf.vMidID, m_vvLocMid, BF::numCo); + CopyCornerByMidID(bf.vGloPos, bf.vMidID, m_vvGloMid, BF::numCo); + + // integration point + AveragePositions(bf.localIP, bf.vLocPos, BF::numCo); + AveragePositions(bf.globalIP, bf.vGloPos, BF::numCo); + + // normal on scvf + traits::NormalOnBF(bf.Normal, bf.vGloPos, m_vvGloMid[0]); + + // compute volume + bf.Vol = VecTwoNorm(bf.Normal); + + // compute shapes and grads + bf.numSH = TrialSpace.num_sh(); + TrialSpace.shapes(&(bf.vShape[0]), bf.localIP); + TrialSpace.grads(&(bf.vLocalGrad[0]), bf.localIP); + + // get reference mapping + rMapping.jacobian_transposed_inverse(bf.JtInv, bf.localIP); + bf.detj = rMapping.sqrt_gram_det(bf.localIP); + + // compute global gradients + for(size_t sh = 0 ; sh < bf.num_sh(); ++sh) + MatVecMult(bf.vGlobalGrad[sh], bf.JtInv, bf.vLocalGrad[sh]); + + // increase curr_bf + ++curr_bf; + + } // end loop of corners of side + + } // end loop sides of element + + } + UG_CATCH_THROW("DimFV1CutGeometry: update_inner_boundary() failed."); + + +} + + + +template +void DimFV1CutGeometry:: +update_boundary_faces(GridObject* pElem, const MathVector* vCornerCoords, const ISubsetHandler* ish) +{ +// get grid + Grid& grid = *(ish->grid()); + +// vector of subset indices of side + std::vector vSubsetIndex; + +// get subset indices for sides (i.e. edge in 2d, faces in 3d) + if(dim == 1) { + std::vector vVertex; + CollectVertices(vVertex, grid, pElem); + vSubsetIndex.resize(vVertex.size()); + for(size_t i = 0; i < vVertex.size(); ++i) + vSubsetIndex[i] = ish->get_subset_index(vVertex[i]); + } + if(dim == 2) { + std::vector vEdges; + CollectEdgesSorted(vEdges, grid, pElem); + vSubsetIndex.resize(vEdges.size()); + for(size_t i = 0; i < vEdges.size(); ++i) + vSubsetIndex[i] = ish->get_subset_index(vEdges[i]); + } + if(dim == 3) { + std::vector vFaces; + CollectFacesSorted(vFaces, grid, pElem); + vSubsetIndex.resize(vFaces.size()); + for(size_t i = 0; i < vFaces.size(); ++i) + vSubsetIndex[i] = ish->get_subset_index(vFaces[i]); + } + + try{ + const DimReferenceElement& rRefElem + = ReferenceElementProvider::get(m_roid); + + DimReferenceMapping& rMapping = ReferenceMappingProvider::get(m_roid); + rMapping.update(vCornerCoords); + + const LocalShapeFunctionSet& TrialSpace = + LocalFiniteElementProvider::get(m_roid, LFEID(LFEID::LAGRANGE, dim, 1)); + +// loop requested subset + typename std::map >::iterator it; + for (it=m_mapVectorBF.begin() ; it != m_mapVectorBF.end(); ++it) + { + // get subset index + const int bndIndex = (*it).first; + + // get vector of BF for element + std::vector& vBF = (*it).second; + + // clear vector + vBF.clear(); + + // current number of bf + size_t curr_bf = 0; + + // loop sides of element + for(size_t side = 0; side < vSubsetIndex.size(); ++side) + { + // skip non boundary sides + if(vSubsetIndex[side] != bndIndex) continue; + + // number of corners of side + const int coOfSide = rRefElem.num(dim-1, side, 0); + + // resize vector + vBF.resize(curr_bf + coOfSide); + + // loop corners + for(int co = 0; co < coOfSide; ++co) + { + // get current bf + BF& bf = vBF[curr_bf]; + + // set node id == scv this bf belongs to + bf.nodeId = rRefElem.id(dim-1, side, 0, co); + + // Compute MidID for BF + ComputeBFMidID(rRefElem, side, bf.vMidID, co); + + // copy corners of bf + CopyCornerByMidID(bf.vLocPos, bf.vMidID, m_vvLocMid, BF::numCo); + CopyCornerByMidID(bf.vGloPos, bf.vMidID, m_vvGloMid, BF::numCo); + + // integration point + AveragePositions(bf.localIP, bf.vLocPos, BF::numCo); + AveragePositions(bf.globalIP, bf.vGloPos, BF::numCo); + + // normal on scvf + traits::NormalOnBF(bf.Normal, bf.vGloPos, m_vvGloMid[0]); + + // compute volume + bf.Vol = VecTwoNorm(bf.Normal); + + // compute shapes and grads + bf.numSH = TrialSpace.num_sh(); + TrialSpace.shapes(&(bf.vShape[0]), bf.localIP); + TrialSpace.grads(&(bf.vLocalGrad[0]), bf.localIP); + + // get reference mapping + rMapping.jacobian_transposed_inverse(bf.JtInv, bf.localIP); + bf.detj = rMapping.sqrt_gram_det(bf.localIP); + + // compute global gradients + for(size_t sh = 0 ; sh < bf.num_sh(); ++sh) + MatVecMult(bf.vGlobalGrad[sh], bf.JtInv, bf.vLocalGrad[sh]); + + // increase curr_bf + ++curr_bf; + } + } + } + + } + UG_CATCH_THROW("DimFV1CutGeometry: update failed."); +} + +////////////////////// +// FV1CutGeometry + +template class FV1CutGeometry; +template class FV1CutGeometry; +template class FV1CutGeometry; + +template class FV1CutGeometry; +template class FV1CutGeometry; + +template class FV1CutGeometry; +template class FV1CutGeometry; + +template class FV1CutGeometry; +template class FV1CutGeometry; +template class FV1CutGeometry; +template class FV1CutGeometry; +template class FV1CutGeometry; + +////////////////////// +// DimFV1CutGeometry +template class DimFV1CutGeometry<1, 1, InterfaceHandlerLocalDiffusion<1> >; + +template class DimFV1CutGeometry<2, 2, InterfaceHandlerLocalDiffusion<2> >; + +template class DimFV1CutGeometry<3, 3, InterfaceHandlerLocalDiffusion<3> >; + + +} // end namespace ug + +#endif /* __H__UG__LIB_DISC__SPATIAL_DISC__DISC_HELPER__FV1Cut_GEOMETRY_IMPL_ */ diff --git a/ugbase/lib_disc/spatial_disc/disc_util/fv1Cut_geom.h b/ugbase/lib_disc/spatial_disc/disc_util/fv1Cut_geom.h new file mode 100644 index 000000000..b5724adf3 --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/disc_util/fv1Cut_geom.h @@ -0,0 +1,1356 @@ +/* + * Copyright (c) 2010-2015: G-CSC, Goethe University Frankfurt + * Author: Andreas Vogel + * + * This file is part of UG4. + * + * UG4 is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License version 3 (as published by the + * Free Software Foundation) with the following additional attribution + * requirements (according to LGPL/GPL v3 §7): + * + * (1) The following notice must be displayed in the Appropriate Legal Notices + * of covered and combined works: "Based on UG4 (www.ug4.org/license)". + * + * (2) The following notice must be displayed at a prominent place in the + * terminal output of covered works: "Based on UG4 (www.ug4.org/license)". + * + * (3) The following bibliography is recommended for citation and must be + * preserved in all covered files: + * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively + * parallel geometric multigrid solver on hierarchically distributed grids. + * Computing and visualization in science 16, 4 (2013), 151-164" + * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel + * flexible software system for simulating pde based models on high performance + * computers. Computing and visualization in science 16, 4 (2013), 165-179" + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +#ifndef __H__UG__LIB_DISC__SPATIAL_DISC__DISC_HELPER__FV1CUT_GEOMETRY__ +#define __H__UG__LIB_DISC__SPATIAL_DISC__DISC_HELPER__FV1CUT_GEOMETRY__ + +// extern libraries +#include +#include +#include + +// other ug4 modules +#include "common/common.h" + +// library intern includes +#include "lib_grid/tools/subset_handler_interface.h" +#include "lib_disc/reference_element/reference_element.h" +#include "lib_disc/reference_element/reference_element_traits.h" +#include "lib_disc/reference_element/reference_mapping.h" +#include "lib_disc/reference_element/reference_mapping_provider.h" +#include "lib_disc/local_finite_element/local_finite_element_provider.h" +#include "lib_disc/common/local_algebra.h" +#include "lib_disc/local_finite_element/lagrange/lagrangep1.h" +#include "lib_disc/quadrature/gauss/gauss_quad.h" +#include "fv_util.h" +#include "fv_geom_base.h" + +#include "lib_disc/spatial_disc/immersed_util/cut_element_handler/cut_element_handler.h" +#include "lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/interface_handler_diffusion.h" + + +namespace ug{ + +//template +//class InterfaceHandlerLocalDiffusion; + +//////////////////////////////////////////////////////////////////////////////// +// FV1Cut Geometry for Reference Element Type +//////////////////////////////////////////////////////////////////////////////// + +/// Geometry and shape functions for 1st order Vertex-Centered Finite Volume +/** + * \tparam TElem Element type + * \tparam TWorldDim (physical) world dimension + */ +template < typename TElem, int TWorldDim> +class FV1CutGeometry : public FVGeometryBase +{ + public: + /// type of element + typedef TElem elem_type; + + /// type of reference element + typedef typename reference_element_traits::reference_element_type ref_elem_type; + + /// used traits + typedef fv1_traits traits; + + public: + /// dimension of reference element + static const int dim = ref_elem_type::dim; + + /// dimension of world + static const int worldDim = TWorldDim; + + /// Hanging node flag: this Geometry does not support hanging nodes + static const bool usesHangingNodes = false; + + /// flag indicating if local data may change + static const bool staticLocalData = true; + + public: + /// order + static const int order = 1; + + /// number of SubControlVolumes + static const size_t numSCV = (ref_elem_type::REFERENCE_OBJECT_ID == ROID_PYRAMID || ref_elem_type::REFERENCE_OBJECT_ID == ROID_OCTAHEDRON) + ? ((ref_elem_type::REFERENCE_OBJECT_ID == ROID_PYRAMID) ? (4*ref_elem_type::numEdges) : 16) : ref_elem_type::numCorners; + + /// type of SubControlVolume + typedef typename traits::scv_type scv_type; + + /// number of SubControlVolumeFaces + static const size_t numSCVF = (ref_elem_type::REFERENCE_OBJECT_ID == ROID_PYRAMID || ref_elem_type::REFERENCE_OBJECT_ID == ROID_OCTAHEDRON) + ? ((ref_elem_type::REFERENCE_OBJECT_ID == ROID_PYRAMID) ? (2*ref_elem_type::numEdges) : 24) : ref_elem_type::numEdges; + + /// type of Shape function used + typedef LagrangeP1 local_shape_fct_set_type; + + /// number of shape functions + static const size_t nsh = local_shape_fct_set_type::nsh; + + /// number of integration points + static const size_t nip = 1; + + public: + /// Sub-Control Volume Face structure + /** + * Each finite element is cut by several sub-control volume faces. The idea + * is that the "dual" skeleton formed by the sub control volume faces of + * all elements again gives rise to a regular mesh with closed + * (lipschitz-bounded) control volumes. The SCVF are the boundary of the + * control volume. In computation the flux over each SCVF must be the same + * in both directions over the face in order to guarantee the conservation + * property. + */ + class SCVF + { + public: + /// Number of corners of scvf + static const size_t numCo = traits::NumCornersOfSCVF; + + public: + SCVF() {} + + /// index of SubControlVolume on one side of the scvf + inline size_t from() const {return From;} + + /// index of SubControlVolume on one side of the scvf + inline size_t to() const {return To;} + + /// normal on scvf (points direction "from"->"to"). Norm is equal to area + inline const MathVector& normal() const {return Normal;} + + /// number of integration points on scvf + inline size_t num_ip() const {return nip;} + + /// local integration point of scvf + inline const MathVector& local_ip() const {return localIP;} + + /// global integration point of scvf + inline const MathVector& global_ip() const {return globalIP;} + + /// Transposed Inverse of Jacobian in integration point + inline const MathMatrix& JTInv() const {return JtInv;} + + /// Determinant of Jacobian in integration point + inline number detJ() const {return detj;} + + /// number of shape functions + inline size_t num_sh() const {return nsh;} + + /// value of shape function i in integration point + inline number shape(size_t sh) const {return vShape[sh];} + + /// vector of shape functions in ip point + inline const number* shape_vector() const {return vShape;} + + /// value of local gradient of shape function i in integration point + inline const MathVector& local_grad(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vLocalGrad[sh];} + + /// vector of local gradients in ip point + inline const MathVector* local_grad_vector() const {return vLocalGrad;} + + /// value of global gradient of shape function i in integration point + inline const MathVector& global_grad(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vGlobalGrad[sh];} + + /// vector of global gradients in ip point + inline const MathVector* global_grad_vector() const {return vGlobalGrad;} + + /// number of corners, that bound the scvf + inline size_t num_corners() const {return numCo;} + + /// return local corner number i + inline const MathVector& local_corner(size_t co) const + {UG_ASSERT(co < num_corners(), "Invalid index."); return vLocPos[co];} + + /// return global corner number i + inline const MathVector& global_corner(size_t co) const + {UG_ASSERT(co < num_corners(), "Invalid index."); return vGloPos[co];} + + private: + // let outer class access private members + friend class FV1CutGeometry; + + // This scvf separates the scv with the ids given in "from" and "to" + // The computed normal points in direction from->to + size_t From, To; + + // The normal on the SCVF pointing (from -> to) + MathVector Normal; // normal (incl. area) + + // ordering is: + // 1D: edgeMidPoint + // 2D: edgeMidPoint, CenterOfElement + // 3D: edgeMidPoint, Side one, CenterOfElement, Side two + MathVector vLocPos[numCo]; // local corners of scvf + MathVector vGloPos[numCo]; // global corners of scvf + MidID vMidID[numCo]; // dimension and id of object, that's midpoint bounds the scvf + + // scvf part + MathVector localIP; // local integration point + MathVector globalIP; // global integration point + + // shapes and derivatives + number vShape[nsh]; // shapes at ip + MathVector vLocalGrad[nsh]; // local grad at ip + MathVector vGlobalGrad[nsh]; // global grad at ip + MathMatrix JtInv; // Jacobian transposed at ip + number detj; // Jacobian det at ip + }; + + /// sub control volume structure + class SCV + { + public: + /// Number of corners of scvf + static const size_t numCo = traits::NumCornersOfSCV; + + public: + SCV() {}; + + /// volume of scv + inline number volume() const {return Vol;} + + /// number of corners, that bound the scvf + inline size_t num_corners() const {return numCo;} + + /// return local corner number i + inline const MathVector& local_corner(size_t co) const + {UG_ASSERT(co < num_corners(), "Invalid index."); return vLocPos[co];} + + /// return global corner number i + inline const MathVector& global_corner(size_t co) const + {UG_ASSERT(co < num_corners(), "Invalid index."); return vGloPos[co];} + + /// return local corners + inline const MathVector* local_corners() const + {return &vLocPos[0];} + + /// return global corners + inline const MathVector* global_corners() const + {return &vGloPos[0];} + + /// node id that this scv is associated to + inline size_t node_id() const {return nodeId;} + + /// number of integration points + inline size_t num_ip() const {return nip;} + + /// local integration point of scv + inline const MathVector& local_ip() const {return vLocPos[0];} + + /// global integration point + inline const MathVector& global_ip() const {return vGloPos[0];} + + /// Transposed Inverse of Jacobian in integration point + inline const MathMatrix& JTInv() const {return JtInv;} + + /// Determinant of Jacobian in integration point + inline number detJ() const {return detj;} + + /// number of shape functions + inline size_t num_sh() const {return nsh;} + + /// value of shape function i in integration point + inline number shape(size_t sh) const {return vShape[sh];} + + /// vector of shape functions in ip point + inline const number* shape_vector() const {return vShape;} + + /// value of local gradient of shape function i in integration point + inline const MathVector& local_grad(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vLocalGrad[sh];} + + /// vector of local gradients in ip point + inline const MathVector* local_grad_vector() const {return vLocalGrad;} + + /// value of global gradient of shape function i in integration point + inline const MathVector& global_grad(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vGlobalGrad[sh];} + + /// vector of global gradients in ip point + inline const MathVector* global_grad_vector() const {return vGlobalGrad;} + + private: + // let outer class access private members + friend class FV1CutGeometry; + + // node id of associated node + size_t nodeId; + + // volume of scv + number Vol; + + // local and global positions of this element + MathVector vLocPos[numCo]; // local position of node + MathVector vGloPos[numCo]; // global position of node + MidID midId[numCo]; // dimension and id of object, that's midpoint bounds the scv + + // shapes and derivatives + number vShape[nsh]; // shapes at ip + MathVector vLocalGrad[nsh]; // local grad at ip + MathVector vGlobalGrad[nsh]; // global grad at ip + MathMatrix JtInv; // Jacobian transposed at ip + number detj; // Jacobian det at ip + }; + + /// boundary face + class BF + { + public: + /// Number of corners of bf + static const size_t numCo = traits::NumCornersOfBF; + + public: + BF() {} + + /// index of SubControlVolume of the bf + inline size_t node_id() const {return nodeId;} + + /// number of integration points on bf + inline size_t num_ip() const {return nip;} + + /// local integration point of bf + inline const MathVector& local_ip() const {return localIP;} + + /// global integration point of bf + inline const MathVector& global_ip() const {return globalIP;} + + /// outer normal on bf. Norm is equal to area + inline const MathVector& normal() const {return Normal;} // includes area + + /// volume of bf + inline number volume() const {return Vol;} + + /// Transposed Inverse of Jacobian in integration point + inline const MathMatrix& JTInv() const {return JtInv;} + + /// Determinant of Jacobian in integration point + inline number detJ() const {return detj;} + + /// number of shape functions + inline size_t num_sh() const {return nsh;} + + /// value of shape function i in integration point + inline number shape(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vShape[sh];} + + /// vector of local gradients in ip point + inline const number* shape_vector() const {return vShape;} + + /// value of local gradient of shape function i in integration point + inline const MathVector& local_grad(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vLocalGrad[sh];} + + /// vector of local gradients in ip point + inline const MathVector* local_grad_vector() const {return vLocalGrad;} + + /// value of global gradient of shape function i in integration point + inline const MathVector& global_grad(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vGlobalGrad[sh];} + + /// vector of global gradients in ip point + inline const MathVector* global_grad_vector() const {return vGlobalGrad;} + + /// number of corners, that bound the scvf + inline size_t num_corners() const {return numCo;} + + /// return local corner number i + inline const MathVector& local_corner(size_t co) const + {UG_ASSERT(co < num_corners(), "Invalid index."); return vLocPos[co];} + + /// return global corner number i + inline const MathVector& global_corner(size_t co) const + {UG_ASSERT(co < num_corners(), "Invalid index."); return vGloPos[co];} + + private: + /// let outer class access private members + friend class FV1CutGeometry; + + // id of scv this bf belongs to + size_t nodeId; + + // ordering is: + // 1D: edgeMidPoint + // 2D: edgeMidPoint, CenterOfElement + // 3D: edgeMidPoint, Side one, CenterOfElement, Side two + MathVector vLocPos[numCo]; // local corners of bf + MathVector vGloPos[numCo]; // global corners of bf + MidID vMidID[numCo]; // dimension and id of object, that's midpoint bounds the bf + + // scvf part + MathVector localIP; // local integration point + MathVector globalIP; // global integration point + MathVector Normal; // normal (incl. area) + number Vol; // volume of bf + + // shapes and derivatives + number vShape[nsh]; // shapes at ip + MathVector vLocalGrad[nsh]; // local grad at ip + MathVector vGlobalGrad[nsh]; // global grad at ip + MathMatrix JtInv; // Jacobian transposed at ip + number detj; // Jacobian det at ip + }; + + public: + /// construct object and initialize local values and sizes + FV1CutGeometry(); + + /// update local data + void update_local_data(); + + /// update data for given element + void update(GridObject* elem, const MathVector* vCornerCoords, + const ISubsetHandler* ish = NULL); + + /// update boundary data for given element + void update_boundary_faces(GridObject* elem, + const MathVector* vCornerCoords, + const ISubsetHandler* ish = NULL); + + /// get the element + TElem* elem() const {return m_pElem;} + + /// get vector of the global coordinates of corners for current element + const MathVector* corners() const {return m_vvGloMid[0];} + + /// number of SubControlVolumeFaces + size_t num_scvf() const {return numSCVF;}; + + /// const access to SubControlVolumeFace number i + const SCVF& scvf(size_t i) const + {UG_ASSERT(i < num_scvf(), "Invalid Index."); return m_vSCVF[i];} + + /// number of SubControlVolumes + // do not use this method to obtain the number of shape functions, + // since this is NOT the same for pyramids; use num_sh() instead. + size_t num_scv() const {return numSCV;} + + /// const access to SubControlVolume number i + const SCV& scv(size_t i) const + {UG_ASSERT(i < num_scv(), "Invalid Index."); return m_vSCV[i];} + + /// number of shape functions + size_t num_sh() const {return nsh;}; + + /// returns reference object id + ReferenceObjectID roid() const {return ref_elem_type::REFERENCE_OBJECT_ID;} + + + public: + /// returns number of all scvf ips + size_t num_scvf_ips() const {return numSCVF;} + + /// returns all ips of scvf as they appear in scv loop + const MathVector* scvf_local_ips() const {return m_vLocSCVF_IP;} + + /// returns all ips of scvf as they appear in scv loop + const MathVector* scvf_global_ips() const {return m_vGlobSCVF_IP;} + + /// returns number of all scv ips + size_t num_scv_ips() const {return numSCV;} + + /// returns all ips of scv as they appear in scv loop + const MathVector* scv_local_ips() const { + if(ref_elem_type::REFERENCE_OBJECT_ID == ROID_PYRAMID || ref_elem_type::REFERENCE_OBJECT_ID == ROID_OCTAHEDRON) + return &(m_vLocSCV_IP[0]); + else + return &(m_vvLocMid[0][0]); + } + + /// returns all ips of scv as they appear in scv loop + const MathVector* scv_global_ips() const { + if(ref_elem_type::REFERENCE_OBJECT_ID == ROID_PYRAMID || ref_elem_type::REFERENCE_OBJECT_ID == ROID_OCTAHEDRON) + return &(m_vGlobSCV_IP[0]); + else + return &(m_vvGloMid[0][0]); + } + + /// return local coords for node ID + const MathVector& local_node_position(size_t nodeID) const + { + UG_ASSERT(nodeID < (size_t) ref_elem_type::numCorners, "Invalid node id."); + return m_vvLocMid[0][nodeID]; + } + + /// return global coords for node ID + const MathVector& global_node_position(size_t nodeID) const + { + UG_ASSERT(nodeID < (size_t) ref_elem_type::numCorners, "Invalid node id."); + return m_vvGloMid[0][nodeID]; + } + + /// returns the local coordinates of the center of mass of the element + const MathVector* coe_local() const {return &(m_vvLocMid[dim][0]);} + + /// returns the global coordinates of the center of mass of the element + const MathVector* coe_global() const {return &(m_vvGloMid[dim][0]);} + + protected: + // global and local ips on SCVF + MathVector m_vGlobSCVF_IP[numSCVF]; + MathVector m_vLocSCVF_IP[numSCVF]; + + // global and local ips on SCV (only needed for Pyramid and Octahedron) + MathVector m_vGlobSCV_IP[numSCV]; + MathVector m_vLocSCV_IP[numSCV]; + + public: + /// add subset that is interpreted as boundary subset. + inline void add_boundary_subset(int subsetIndex) {m_mapVectorBF[subsetIndex];} + + /// removes subset that is interpreted as boundary subset. + inline void remove_boundary_subset(int subsetIndex) {m_mapVectorBF.erase(subsetIndex);} + + /// reset all boundary subsets + inline void clear_boundary_subsets() {m_mapVectorBF.clear();} + + /// number of registered boundary subsets + inline size_t num_boundary_subsets() {return m_mapVectorBF.size();} + + /// number of all boundary faces + inline size_t num_bf() const + { + typename std::map >::const_iterator it; + size_t num = 0; + for ( it=m_mapVectorBF.begin() ; it != m_mapVectorBF.end(); it++ ) + num += (*it).second.size(); + return num; + } + + /// number of boundary faces on subset 'subsetIndex' + inline size_t num_bf(int si) const + { + typename std::map >::const_iterator it; + it = m_mapVectorBF.find(si); + if(it == m_mapVectorBF.end()) return 0; + else return (*it).second.size(); + } + + /// returns the boundary face i for subsetIndex + inline const BF& bf(int si, size_t i) const + { + UG_ASSERT(i < num_bf(si), "Invalid index."); + typename std::map >::const_iterator it; + it = m_mapVectorBF.find(si); + if(it == m_mapVectorBF.end()) UG_THROW("FVGeom: No bnd face for subset"<& bf(int si) const + { + typename std::map >::const_iterator it; + it = m_mapVectorBF.find(si); + if(it == m_mapVectorBF.end()) return m_vEmptyVectorBF; + return (*it).second; + } + + void reset_curr_elem() {m_pElem = NULL;} + + protected: + std::map > m_mapVectorBF; + std::vector m_vEmptyVectorBF; + + private: + /// pointer to current element + TElem* m_pElem; + + /// max number of geom objects in all dimensions + // (most objects in 1 dim, i.e. number of edges, but +1 for 1D) + static const int maxMid = numSCVF + 1; + + /// local and global geom object midpoints for each dimension + MathVector m_vvLocMid[dim+1][maxMid]; + MathVector m_vvGloMid[dim+1][maxMid]; + + /// SubControlVolumeFaces + SCVF m_vSCVF[numSCVF]; + + /// SubControlVolumes + SCV m_vSCV[numSCV]; + + /// Reference Mapping + ReferenceMapping m_mapping; + + /// Reference Element + const ref_elem_type& m_rRefElem; + + /// Shape function set + const local_shape_fct_set_type& m_rTrialSpace; +}; + +//////////////////////////////////////////////////////////////////////////////// +// Dim-dependent Finite Volume Geometry +//////////////////////////////////////////////////////////////////////////////// + +/// Geometry and shape functions for 1st order Vertex-Centered Finite Volume +/** + * \tparam TDim reference element dim + * \tparam TWorldDim (physical) world dimension + */ +template > +class DimFV1CutGeometry : public FVGeometryBase +{ + public: + /// used traits + typedef fv1_dim_traits traits; + + public: + /// dimension of reference element + static const int dim = TDim; + + /// dimension of world + static const int worldDim = TWorldDim; + + /// Hanging node flag: this Geometry does not support hanging nodes + static const bool usesHangingNodes = false; + + /// flag indicating if local data may change + static const bool staticLocalData = false; + + public: + /// order + static const int order = 1; + + /// number of SubControlVolumes + static const size_t maxNumSCV = traits::maxNumSCV; + + /// type of SubControlVolume + typedef typename traits::scv_type scv_type; + + /// max number of SubControlVolumeFaces + static const size_t maxNumSCVF = traits::maxNumSCVF; + + /// max number of shape functions + static const size_t maxNSH = traits::maxNSH; + + /// number of integration points + static const size_t nip = 1; + + public: + /// Sub-Control Volume Face structure + /** + * Each finite element is cut by several sub-control volume faces. The idea + * is that the "dual" skeleton formed by the sub control volume faces of + * all elements again gives rise to a regular mesh with closed + * (lipschitz-bounded) control volumes. The SCVF are the boundary of the + * control volume. In computation the flux over each SCVF must be the same + * in both directions over the face in order to guarantee the conservation + * property. + */ + class SCVF + { + public: + /// Number of corners of scvf + static const size_t numCo = traits::NumCornersOfSCVF; + + public: + SCVF() {} + + /// index of SubControlVolume on one side of the scvf + inline size_t from() const {return From;} + + /// index of SubControlVolume on one side of the scvf + inline size_t to() const {return To;} + + /// number of integration points on scvf + inline size_t num_ip() const {return nip;} + + /// local integration point of scvf + inline const MathVector& local_ip() const {return localIP;} + + /// global integration point of scvf + inline const MathVector& global_ip() const {return globalIP;} + + /// normal on scvf (points direction "from"->"to"). Norm is equal to area + inline const MathVector& normal() const {return Normal;} + + /// Transposed Inverse of Jacobian in integration point + inline const MathMatrix& JTInv() const {return JtInv;} + + /// Determinant of Jacobian in integration point + inline number detJ() const {return detj;} + + /// number of shape functions + inline size_t num_sh() const {return numSH;} + + /// value of shape function i in integration point + inline number shape(size_t sh) const {return vShape[sh];} + + /// vector of shape functions in ip point + inline const number* shape_vector() const {return vShape;} + + /// value of local gradient of shape function i in integration point + inline const MathVector& local_grad(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vLocalGrad[sh];} + + /// vector of local gradients in ip point + inline const MathVector* local_grad_vector() const {return vLocalGrad;} + + /// value of global gradient of shape function i in integration point + inline const MathVector& global_grad(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vGlobalGrad[sh];} + + /// vector of gloabl gradients in ip point + inline const MathVector* global_grad_vector() const {return vGlobalGrad;} + + /// number of corners, that bound the scvf + inline size_t num_corners() const {return numCo;} + + /// return local corner number i + inline const MathVector& local_corner(size_t co) const + {UG_ASSERT(co < num_corners(), "Invalid index."); return vLocPos[co];} + + /// return glbal corner number i + inline const MathVector& global_corner(size_t co) const + {UG_ASSERT(co < num_corners(), "Invalid index."); return vGloPos[co];} + + private: + // let outer class access private members + friend class DimFV1CutGeometry; + + // This scvf separates the scv with the ids given in "from" and "to" + // The computed normal points in direction from->to + size_t From, To; + + // The normal on the SCVF pointing (from -> to) + MathVector Normal; // normal (incl. area) + + // ordering is: + // 1D: edgeMidPoint + // 2D: edgeMidPoint, CenterOfElement + // 3D: edgeMidPoint, Side one, CenterOfElement, Side two + MathVector vLocPos[numCo]; // local corners of scvf + MathVector vGloPos[numCo]; // global corners of scvf + MidID vMidID[numCo]; // dimension and id of object, that's midpoint bounds the scvf + + // scvf part + MathVector localIP; // local integration point + MathVector globalIP; // global integration point + + // shapes and derivatives + size_t numSH; + number vShape[maxNSH]; // shapes at ip + MathVector vLocalGrad[maxNSH]; // local grad at ip + MathVector vGlobalGrad[maxNSH]; // global grad at ip + MathMatrix JtInv; // Jacobian transposed at ip + number detj; // Jacobian det at ip + }; + + /// sub control volume structure + class SCV + { + public: + /// Number of corners of scv + static const size_t numCo = traits::NumCornersOfSCV; + + public: + SCV() {}; + + /// volume of scv + inline number volume() const {return Vol;} + + inline number get_volume(size_t ip) const + { + if ( volIP[0] == 0.0 && volIP[1] != 0.0 ) + UG_THROW("1: error in volIP!\n"); + if ( volIP[0] != 0.0 && volIP[1] == 0.0 ) + UG_THROW("2: error in volIP!\n"); + + if ( volIP[0] == 0.0 && volIP[1] == 0.0 ) + return Vol; + + return volIP[ip]; + } + + /// number of corners, that bound the scv + inline size_t num_corners() const {return numCo;} + + /// return local corner number i + inline const MathVector& local_corner(size_t co) const + {UG_ASSERT(co < num_corners(), "Invalid index."); return vLocPos[co];} + + /// return global corner number i + inline const MathVector& global_corner(size_t co) const + {UG_ASSERT(co < num_corners(), "Invalid index."); return vGloPos[co];} + + /// node id that this scv is associated to + inline size_t node_id() const {return nodeId;} + + /// number of integration points + inline size_t num_ip() const {return nip;} + + /// local integration point of scv + inline const MathVector& local_ip() const {return vLocPos[0];} + + /// global integration point + inline const MathVector& global_ip() const {return vGloPos[0];} + + /// Transposed Inverse of Jacobian in integration point + inline const MathMatrix& JTInv() const {return JtInv;} + + /// Determinant of Jacobian in integration point + inline number detJ() const {return detj;} + + /// number of shape functions + inline size_t num_sh() const {return numSH;} + + /// value of shape function i in integration point + inline number shape(size_t sh) const {return vShape[sh];} + + /// vector of shape functions in ip point + inline const number* shape_vector() const {return vShape;} + + /// value of local gradient of shape function i in integration point + inline const MathVector& local_grad(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vLocalGrad[sh];} + + /// vector of local gradients in ip point + inline const MathVector* local_grad_vector() const {return vLocalGrad;} + + /// value of global gradient of shape function i in integration point + inline const MathVector& global_grad(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vGlobalGrad[sh];} + + /// vector of global gradients in ip point + inline const MathVector* global_grad_vector() const {return vGlobalGrad;} + + private: + // let outer class access private members + friend class DimFV1CutGeometry; + + // node id of associated node + size_t nodeId; + + // volume of scv + number Vol; + number volIP[2]; + + // local and global positions of this element + MathVector vLocPos[numCo]; // local position of node + MathVector vGloPos[numCo]; // global position of node + MidID vMidID[numCo]; // dimension and id of object, that's midpoint bounds the scv + + // shapes and derivatives + size_t numSH; + number vShape[maxNSH]; // shapes at ip + MathVector vLocalGrad[maxNSH]; // local grad at ip + MathVector vGlobalGrad[maxNSH]; // global grad at ip + MathMatrix JtInv; // Jacobian transposed at ip + number detj; // Jacobian det at ip + }; + + /// boundary face + class BF + { + public: + /// Number of corners of bf + static const size_t numCo = traits::NumCornersOfSCVF; + + public: + BF() {} + + /// index of SubControlVolume of the bf + inline size_t node_id() const {return nodeId;} + + /// number of integration points on bf + inline size_t num_ip() const {return nip;} + + /// local integration point of bf + inline const MathVector& local_ip() const {return localIP;} + + /// global integration point of bf + inline const MathVector& global_ip() const {return globalIP;} + + /// outer normal on bf. Norm is equal to area + inline const MathVector& normal() const {return Normal;} // includes area + + /// volume of bf + inline number volume() const {return Vol;} + + /// Transposed Inverse of Jacobian in integration point + inline const MathMatrix& JTInv() const {return JtInv;} + + /// Determinant of Jacobian in integration point + inline number detJ() const {return detj;} + + /// number of shape functions + inline size_t num_sh() const {return numSH;} + + /// value of shape function i in integration point + inline number shape(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vShape[sh];} + + /// vector of local gradients in ip point + inline const number* shape_vector() const {return vShape;} + + /// value of local gradient of shape function i in integration point + inline const MathVector& local_grad(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vLocalGrad[sh];} + + /// vector of local gradients in ip point + inline const MathVector* local_grad_vector() const {return vLocalGrad;} + + /// value of global gradient of shape function i in integration point + inline const MathVector& global_grad(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vGlobalGrad[sh];} + + /// vector of global gradients in ip point + inline const MathVector* global_grad_vector() const {return vGlobalGrad;} + + /// number of corners, that bound the scvf + inline size_t num_corners() const {return numCo;} + + /// return local corner number i + inline const MathVector& local_corner(size_t co) const + {UG_ASSERT(co < num_corners(), "Invalid index."); return vLocPos[co];} + + /// return global corner number i + inline const MathVector& global_corner(size_t co) const + {UG_ASSERT(co < num_corners(), "Invalid index."); return vGloPos[co];} + + number Vol; // volume of bf + + private: + /// let outer class access private members + friend class DimFV1CutGeometry; + + // id of scv this bf belongs to + size_t nodeId; + + // ordering is: + // 1D: edgeMidPoint + // 2D: edgeMidPoint, CenterOfElement + // 3D: edgeMidPoint, Side one, CenterOfElement, Side two + MathVector vLocPos[numCo]; // local corners of bf + MathVector vGloPos[numCo]; // global corners of bf + MidID vMidID[numCo]; // dimension and id of object, that's midpoint bounds the bf + + // scvf part + MathVector localIP; // local integration point + MathVector globalIP; // global integration point + MathVector Normal; // normal (incl. area) + + // shapes and derivatives + size_t numSH; + number vShape[maxNSH]; // shapes at ip + MathVector vLocalGrad[maxNSH]; // local grad at ip + MathVector vGlobalGrad[maxNSH]; // global grad at ip + MathMatrix JtInv; // Jacobian transposed at ip + number detj; // Jacobian det at ip + }; + + public: + /// construct object and initialize local values and sizes + DimFV1CutGeometry() : m_pElem(NULL), m_roid(ROID_UNKNOWN) {}; + + //////////////////////////////////////////////////////////////////////////////////////// + /// new methods for the special cut-Geometry + //////////////////////////////////////////////////////////////////////////////////////// + + std::vector& get_boundary_faces() + { return m_spInterfaceHandler->get_boundary_faces(); } + void clear_boundary_faces() { m_spInterfaceHandler->clear_boundary_faces(); } + + inline void set_element_modus(bool boolian) { mElemModus = boolian;} + inline const bool get_element_modus() { return mElemModus;} + inline const ReferenceObjectID get_roid() const {return m_roid;} + + inline const size_t get_original_node(size_t i) const {return m_spInterfaceHandler->corner_orig(i);} + inline const size_t get_interface_id(size_t i) + { + std::vector interfaceIDs = m_spInterfaceHandler->interface_id_all(); + return get_original_node(interfaceIDs[i]); + } + bool lies_onInterface(const size_t newID) + { return m_spInterfaceHandler->lies_onInterface(newID); } + + inline MathVector get_corner(size_t i) {return m_spInterfaceHandler->corner(i);} + + number get_shape(size_t sh, MathVector locIP, const ReferenceObjectID roid ) + { + const LocalShapeFunctionSet& TrialSpace = + LocalFiniteElementProvider::get(roid, LFEID(LFEID::LAGRANGE, dim, 1)); + + return TrialSpace.shape(sh, locIP); + } + + ///////////////////////////////////////////////////////////////////////////////////////////// + /// methods necessary to get access to methods of the InterfaceHandler via the + /// FV1CutGeom-object 'TFVGeom& geo' within the 'ConvectionDiffusionFV1_cutElem'-class + + ///////////////////////////////////////////////////////////////////////////////////////////// + // (A) 'integral'-methods for the computation of the l2-error within + // 'ConvectionDiffusionFV1_cutElem::add_l2error_A_elem()' + inline void L2Error_add(const number value) + { return m_spInterfaceHandler->L2Error_add(value); } + inline number get_L2Error() + { return m_spInterfaceHandler->get_L2Error(); } + inline void L2Error_init() + { m_spInterfaceHandler->L2Error_init(); } + + ///////////////////////////////////////////////////////////////////////////////////////////// + /// (B) further methods + void resize_local_data(LocalVector u) + { m_spInterfaceHandler->resize_local_data(u); } + void set_orientation(const int orientation) + { m_spInterfaceHandler->set_orientation(orientation); } + int get_orientation() + { return m_spInterfaceHandler->get_orientation(); } + const bool get_boolian_for_diffusion() + { return m_spInterfaceHandler->get_boolian_for_diffusion(); } + + + // tags needed within the class 'DiffusionInterfaceMapper' + void set_DoF_tag(const bool bFactor2_for_DoFIndex, const ReferenceObjectID roid) + { m_spInterfaceHandler->set_DoF_tag(bFactor2_for_DoFIndex, roid); } + + // shiftTag = true in case of double DoFs on interface! + bool get_bScaleDoFs() { return m_spInterfaceHandler->get_bScaleDoFs(); } + + inline const bool get_bNearInterface() + { return m_spInterfaceHandler->get_bNearInterface(); } + ///////////////////////////////////////////////////////////////////////////////////////////// + // (C) access methods for assemgling of the local defect and jacobian for + // the elem Disc 'ConvectionDiffusionFV1_cutElem': + // --> during call of 'add_jac_A_elem()' and 'add_def_A_elem()' + + + /// setter methods + void set_jacobian(const LocalMatrix locJ, const ReferenceObjectID roid) + { m_spInterfaceHandler->set_jacobian(locJ, roid); } + + void set_defect(const LocalVector locD, const ReferenceObjectID roid) + { m_spInterfaceHandler->set_defect(locD, roid); } + + /// getter methods + LocalMatrix& get_jacobian(const ReferenceObjectID roid) + { return m_spInterfaceHandler->get_local_jacobian(roid); } + + LocalVector& get_defect(const ReferenceObjectID roid) + { return m_spInterfaceHandler->get_local_defect(roid); } + + LocalVector& get_solution(const ReferenceObjectID roid) + { return m_spInterfaceHandler->get_local_solution(roid); } + + /// reset methods + void reset_defect_on_interface(LocalVector& locD, const size_t size) + { m_spInterfaceHandler->reset_defect_on_interface(locD, size); } + + void reset_jacobian_on_interface(LocalMatrix& locJ, const size_t size) + { m_spInterfaceHandler->reset_jacobian_on_interface(locJ, size); } + + + + ///////////////////////////////////////////////////////////////////////////////////////////// + // (D) access methods for local assembling of the boundary conditions on the + // immersed interface into the defect and jacobian for the elem Disc + // 'ConvectionDiffusionFV1_cutElem' + // --> during call of 'add_jac_A_elem()' and 'add_def_A_elem()' + + // getter methods + number get_diffusion() + { return m_spInterfaceHandler->get_diffusion(); } + number get_diffusion(const bool bElementIsOutside) + { return m_spInterfaceHandler->get_diffusion(bElementIsOutside); } + + // setter methods (called by ConvectionDiffusionFV1_cutElem::get_local_data() ) + void set_local_sol(LocalVector& solU, const size_t size, const LocalVector& lvec, + const int orientation) + { return m_spInterfaceHandler->set_local_sol(solU, size, lvec, orientation); } + + void set_jump_values(LocalVector& jumpOut, LocalIndices ind, const size_t size) + { m_spInterfaceHandler->set_jump_values(jumpOut, ind, size); } + + void set_jump_grad_values(LocalVector& jumpGradOut, LocalIndices ind, const size_t size) + { m_spInterfaceHandler->set_jump_grad_values(jumpGradOut, ind, size); } + + // 'set_source' instance used for diffusion elem disc + void set_source(const std::vector sourceIm, LocalVector& sourceOut, LocalIndices ind, + const size_t size, const bool bElementIsCut) + { m_spInterfaceHandler->set_source(sourceIm, sourceOut, ind, size, bElementIsCut); } + + + ///////////////////////////////////////////////////////////////////////////////////////////// + // (E) methods for Nitsche + void print_Nitsche_Data() { return m_spInterfaceHandler->print_Nitsche_Data(); } + number vAlpha(size_t i, size_t j) { return m_spInterfaceHandler->vAlpha(i,j); } + MathVector vIntersectionPnts(size_t i) { return m_spInterfaceHandler->vIntersectionPnts(i); } + MathMatrix ShapeValues() { return m_spInterfaceHandler->vShapeValues(); } + MathVector NormalToFace() { return m_spInterfaceHandler->NormalToFace(); } + number Gamma() { return m_spInterfaceHandler->Gamma(); } + number Area() { return m_spInterfaceHandler->Area(); } + number AreaOrig() { return m_spInterfaceHandler->AreaOrig(); } + number AreaScale() { return m_spInterfaceHandler->AreaScale(); } + number IntegralGamma(size_t i) { return m_spInterfaceHandler->IntegralGamma(i); } + + + /// called during 'ParticleBndCond::add_def_M_local()': + const number volume_fem_elem() const {UG_THROW("FV1CutGeom::volume_fem_elem() not implemented!\n");} + const number volume_FT_elem() const {UG_THROW("FV1CutGeom::volume_FT_elem() not implemented!\n");} + + number get_volume(size_t ip) const { return m_vVol_IP[ip]; } + + bool mElemModus; + + /// set the local interface handler + /// (called during constructor of class 'ImmersedInterface') + void set_interface_handler(SmartPtr localHandler) + { m_spInterfaceHandler = localHandler; } + + + ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// + + + /// update data for given element + void update(GridObject* elem, const MathVector* vCornerCoords, + const ISubsetHandler* ish = NULL); + + /// update boundary data for given element + void update_boundary_faces(GridObject* elem, + const MathVector* vCornerCoords, + const ISubsetHandler* ish = NULL); + + /// get the element + GridObject* elem() const {return m_pElem;} + + /// get vector of corners for current element + const MathVector* corners() const {return m_vvGloMid[0];} + + /// number of SubControlVolumeFaces + size_t num_scvf() const {return m_numSCVF;}; + + /// const access to SubControlVolumeFace number i + const SCVF& scvf(size_t i) const + {UG_ASSERT(i < num_scvf(), "Invalid Index."); return m_vSCVF[i];} + + /// number of SubControlVolumes + // do not use this method to obtain the number of shape functions, + // since this is NOT the same for pyramids; use num_sh() instead. + size_t num_scv() const {return m_numSCV;} + + /// const access to SubControlVolume number i + const SCV& scv(size_t i) const + {UG_ASSERT(i < num_scv(), "Invalid Index."); return m_vSCV[i];} + + /// number of shape functions + size_t num_sh() const {return m_nsh;}; + + public: + /// returns number of all scvf ips + size_t num_scvf_ips() const {return m_numSCVF;} + + /// returns all ips of scvf as they appear in scv loop + const MathVector* scvf_local_ips() const {return m_vLocSCVF_IP;} + + /// returns all ips of scvf as they appear in scv loop + const MathVector* scvf_global_ips() const {return m_vGlobSCVF_IP;} + + /// returns number of all scv ips + size_t num_scv_ips() const {return m_numSCV;} + + /// returns all ips of scv as they appear in scv loop + const MathVector* scv_local_ips() const { + if(m_roid == ROID_PYRAMID || m_roid == ROID_OCTAHEDRON) + return &(m_vLocSCV_IP[0]); + else + return &(m_vvLocMid[0][0]); + } + + /// returns all ips of scv as they appear in scv loop + const MathVector* scv_global_ips() const { + if(m_roid == ROID_PYRAMID || m_roid == ROID_OCTAHEDRON) + return &(m_vGlobSCV_IP[0]); + else + return &(m_vvGloMid[0][0]); + } + + /// returns the local coordinates of the center of mass of the element + const MathVector* coe_local() const {return &(m_vvLocMid[dim][0]);} + + /// returns the global coordinates of the center of mass of the element + const MathVector* coe_global() const {return &(m_vvGloMid[dim][0]);} + + /// returns reference object id + ReferenceObjectID roid() const {return m_roid;} + + /// update local data + void update_local(ReferenceObjectID roid); + + ////////////////////////////////////////////////////////////////////////////// + /// new FT-methods + ////////////////////////////////////////////////////////////////////////////// + + /// update boundary faces on interface; call during update() + void update_inner_boundary_faces(); + + /// if OUTSIDE_DOM within update() + void set_local_data_to_zero(){ m_numSCVF = m_numSCV = m_nsh = 0;} + +/* ToDo + /// final computations within update() + void remap_shapes_and_derivatives(ReferenceObjectID roid); + + /// computations for remapping SCVF + void copy_SCVF(SCVF vSCVF[maxNumSCVF]); + void remap_add_SCVF(SCVF vSCVF[maxNumSCVF], size_t numSH); + + /// computations for remapping SCV + void copy_SCV(SCV vSCV[maxNumSCV]); + void remap_add_SCV(SCV vSCV[maxNumSCV], size_t numSH); + + /// computations for remapping m_spInterfaceHandler.m_vBF + void copy_BF(BF vBF[maxNumSCV] ); + void remap_BF(BF vBF[maxNumSCV], size_t numSH); + +*/ + + ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// + + + protected: + // global and local ips on SCVF + MathVector m_vGlobSCVF_IP[maxNumSCVF]; + MathVector m_vLocSCVF_IP[maxNumSCVF]; + + // global and local ips on SCV (only needed for Pyramid and Octahedron) + MathVector m_vGlobSCV_IP[maxNumSCV]; + MathVector m_vLocSCV_IP[maxNumSCV]; + + number m_vVol_IP[2]; + + public: + /// add subset that is interpreted as boundary subset. + inline void add_boundary_subset(int subsetIndex) {m_mapVectorBF[subsetIndex];} + + /// removes subset that is interpreted as boundary subset. + inline void remove_boundary_subset(int subsetIndex) {m_mapVectorBF.erase(subsetIndex);} + + /// reset all boundary subsets + inline void clear_boundary_subsets() {m_mapVectorBF.clear();} + + /// number of registered boundary subsets + inline size_t num_boundary_subsets() {return m_mapVectorBF.size();} + + /// number of all boundary faces + inline size_t num_bf() const + { + typename std::map >::const_iterator it; + size_t num = 0; + for ( it=m_mapVectorBF.begin() ; it != m_mapVectorBF.end(); it++ ) + num += (*it).second.size(); + return num; + } + + /// number of boundary faces on subset 'subsetIndex' + inline size_t num_bf(int si) const + { + typename std::map >::const_iterator it; + it = m_mapVectorBF.find(si); + if(it == m_mapVectorBF.end()) return 0; + else return (*it).second.size(); + } + + /// returns the boundary face i for subsetIndex + inline const BF& bf(int si, size_t i) const + { + typename std::map >::const_iterator it; + it = m_mapVectorBF.find(si); + if(it == m_mapVectorBF.end()) UG_THROW("DimFV1CutGeom: No BndSubset "<& bf(int si) const + { + typename std::map >::const_iterator it; + it = m_mapVectorBF.find(si); + if(it == m_mapVectorBF.end()) return m_vEmptyVectorBF; + return (*it).second; + } + + protected: + std::map > m_mapVectorBF; + std::vector m_vEmptyVectorBF; + + private: + /// pointer to current element + GridObject* m_pElem; + + /// current reference object id + ReferenceObjectID m_roid; + + /// current number of scv + size_t m_numSCV; + + /// current number of scvf + size_t m_numSCVF; + + /// current number of shape functions + size_t m_nsh; + + /// max number of geometric objects in a dimension + // (most objects in 1 dim, i.e. number of edges, but +1 for 1D) + static const int maxMid = maxNumSCVF + 1; + + /// local and global geom object midpoints for each dimension + MathVector m_vvLocMid[dim+1][maxMid]; + MathVector m_vvGloMid[dim+1][maxMid]; + + /// SubControlVolumeFaces + SCVF m_vSCVF[maxNumSCVF]; + + /// SubControlVolumes + SCV m_vSCV[maxNumSCV]; + + //////////////////////////////////////////////////////////////////////////////// + // FV1Cut data + //////////////////////////////////////////////////////////////////////////////// + + // InterfaceHandlerLocalDiffusion: derived from class 'IInterfaceHandlerLocal' + SmartPtr m_spInterfaceHandler; + + bool m_bIsFlatTopElement; + + +}; + +} + +#endif /* __H__UG__LIB_DISC__SPATIAL_DISC__DISC_HELPER__FV1CUT_GEOMETRY__ */ diff --git a/ugbase/lib_disc/spatial_disc/disc_util/fv1FT_geom.cpp b/ugbase/lib_disc/spatial_disc/disc_util/fv1FT_geom.cpp new file mode 100644 index 000000000..dd4e986b3 --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/disc_util/fv1FT_geom.cpp @@ -0,0 +1,2011 @@ +/* + * Copyright (c) 2010-2015: G-CSC, Goethe University Frankfurt + * Author: Andreas Vogel + * + * This file is part of UG4. + * + * UG4 is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License version 3 (as published by the + * Free Software Foundation) with the following additional attribution + * requirements (according to LGPL/GPL v3 §7): + * + * (1) The following notice must be displayed in the Appropriate Legal Notices + * of covered and combined works: "Based on UG4 (www.ug4.org/license)". + * + * (2) The following notice must be displayed at a prominent place in the + * terminal output of covered works: "Based on UG4 (www.ug4.org/license)". + * + * (3) The following bibliography is recommended for citation and must be + * preserved in all covered files: + * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively + * parallel geometric multigrid solver on hierarchically distributed grids. + * Computing and visualization in science 16, 4 (2013), 151-164" + * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel + * flexible software system for simulating pde based models on high performance + * computers. Computing and visualization in science 16, 4 (2013), 165-179" + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +#ifndef __H__UG__LIB_DISC__SPATIAL_DISC__DISC_HELPER__FV1FT_GEOMETRY_IMPL_ +#define __H__UG__LIB_DISC__SPATIAL_DISC__DISC_HELPER__FV1FT_GEOMETRY_IMPL_ + +#include "common/util/provider.h" +#include "fv1FT_geom.h" +#include "lib_disc/reference_element/reference_element.h" +#include "lib_disc/quadrature/quadrature.h" +#include "lib_algebra/common/operations_vec.h" + + +namespace ug{ + +/** + * \tparam dim dimension of coordinates + * \tparam TRefElem Reference element type + * \tparam maxMid Maximum number of elements for all dimensions + */ +template +static void ComputeMidPoints(const TRefElem& rRefElem, + const MathVector vCorner[], + MathVector vvMid[][maxMid]) +{ +// compute local midpoints for all geometric objects with 0 < d <= dim + for(int d = 1; d <= dim; ++d) + { + // loop geometric objects of dimension d + for(size_t i = 0; i < rRefElem.num(d); ++i) + { + // set first node + const size_t coID0 = rRefElem.id(d, i, 0, 0); + vvMid[d][i] = vCorner[coID0]; + + // add corner coordinates of the corners of the geometric object + for(size_t j = 1; j < rRefElem.num(d, i, 0); ++j) + { + const size_t coID = rRefElem.id(d, i, 0, j); + vvMid[d][i] += vCorner[coID]; + } + + // scale for correct averaging + vvMid[d][i] *= 1./(rRefElem.num(d, i, 0)); + } + } + +// for OCTAHEDRONS: add midpoints of imaginary faces, edges and volumes +// resulting from the division into 4 tetrahedra alongside inner edge 3->1 + if (rRefElem.roid() == ROID_OCTAHEDRON) + { + // diagonal 3->1, diagonal 1->3 + VecScaleAdd(vvMid[1][rRefElem.num(1)], 0.5, vCorner[3], 0.5, vCorner[1]); + VecScaleAdd(vvMid[1][rRefElem.num(1)+1], 0.5, vCorner[1], 0.5, vCorner[3]); + + // subface 1,2,3; subface 1,3,2; subface 1,3,4; subface 1,4,3; face 1,3,5; face 1,5,3; face 1,0,3; face 1,3,0 + vvMid[2][rRefElem.num(2)] = vCorner[1]; + vvMid[2][rRefElem.num(2)] += vCorner[2]; + vvMid[2][rRefElem.num(2)] += vCorner[3]; + vvMid[2][rRefElem.num(2)] *= 1.0/3.0; + + vvMid[2][rRefElem.num(2)+1] = vCorner[1]; + vvMid[2][rRefElem.num(2)+1] += vCorner[3]; + vvMid[2][rRefElem.num(2)+1] += vCorner[2]; + vvMid[2][rRefElem.num(2)+1] *= 1.0/3.0; + + vvMid[2][rRefElem.num(2)+2] = vCorner[1]; + vvMid[2][rRefElem.num(2)+2] += vCorner[3]; + vvMid[2][rRefElem.num(2)+2] += vCorner[4]; + vvMid[2][rRefElem.num(2)+2] *= 1.0/3.0; + + vvMid[2][rRefElem.num(2)+3] = vCorner[1]; + vvMid[2][rRefElem.num(2)+3] += vCorner[4]; + vvMid[2][rRefElem.num(2)+3] += vCorner[3]; + vvMid[2][rRefElem.num(2)+3] *= 1.0/3.0; + + vvMid[2][rRefElem.num(2)+4] = vCorner[1]; + vvMid[2][rRefElem.num(2)+4] += vCorner[3]; + vvMid[2][rRefElem.num(2)+4] += vCorner[5]; + vvMid[2][rRefElem.num(2)+4] *= 1.0/3.0; + + vvMid[2][rRefElem.num(2)+5] = vCorner[1]; + vvMid[2][rRefElem.num(2)+5] += vCorner[5]; + vvMid[2][rRefElem.num(2)+5] += vCorner[3]; + vvMid[2][rRefElem.num(2)+5] *= 1.0/3.0; + + vvMid[2][rRefElem.num(2)+6] = vCorner[1]; + vvMid[2][rRefElem.num(2)+6] += vCorner[0]; + vvMid[2][rRefElem.num(2)+6] += vCorner[3]; + vvMid[2][rRefElem.num(2)+6] *= 1.0/3.0; + + vvMid[2][rRefElem.num(2)+7] = vCorner[1]; + vvMid[2][rRefElem.num(2)+7] += vCorner[3]; + vvMid[2][rRefElem.num(2)+7] += vCorner[0]; + vvMid[2][rRefElem.num(2)+7] *= 1.0/3.0; + + // subvolume 1,2,3,5; subvolume 1,3,4,5; subvolume 1,2,3,0; subvolume 1,3,4,0 + vvMid[3][rRefElem.num(3)] = vCorner[1]; + vvMid[3][rRefElem.num(3)] += vCorner[2]; + vvMid[3][rRefElem.num(3)] += vCorner[3]; + vvMid[3][rRefElem.num(3)] += vCorner[5]; + vvMid[3][rRefElem.num(3)] *= 0.25; + + vvMid[3][rRefElem.num(3)+1] = vCorner[1]; + vvMid[3][rRefElem.num(3)+1] += vCorner[3]; + vvMid[3][rRefElem.num(3)+1] += vCorner[4]; + vvMid[3][rRefElem.num(3)+1] += vCorner[5]; + vvMid[3][rRefElem.num(3)+1] *= 0.25; + + vvMid[3][rRefElem.num(3)+2] = vCorner[1]; + vvMid[3][rRefElem.num(3)+2] += vCorner[2]; + vvMid[3][rRefElem.num(3)+2] += vCorner[3]; + vvMid[3][rRefElem.num(3)+2] += vCorner[0]; + vvMid[3][rRefElem.num(3)+2] *= 0.25; + + vvMid[3][rRefElem.num(3)+3] = vCorner[1]; + vvMid[3][rRefElem.num(3)+3] += vCorner[3]; + vvMid[3][rRefElem.num(3)+3] += vCorner[4]; + vvMid[3][rRefElem.num(3)+3] += vCorner[0]; + vvMid[3][rRefElem.num(3)+3] *= 0.25; + } +} + +/** + * \param[in] i indicates that scvf corresponds to i'th edge of ref elem + */ +template +static void ComputeSCVFMidID(const TRefElem& rRefElem, + MidID vMidID[], int i) +{ + static const int dim = TRefElem::dim; + + if (rRefElem.roid() != ROID_PYRAMID && rRefElem.roid() != ROID_OCTAHEDRON) + { + // set mid ids + { + // start at edge midpoint + vMidID[0] = MidID(1,i); + + // loop up dimension + if(dim == 2) + { + vMidID[1] = MidID(dim, 0); // center of element + } + else if (dim == 3) + { + vMidID[1] = MidID(2, rRefElem.id(1, i, 2, 0)); // side 0 + vMidID[2] = MidID(dim, 0); // center of element + vMidID[3] = MidID(2, rRefElem.id(1, i, 2, 1)); // side 1 + } + } + } +// pyramid here + else if(rRefElem.roid() == ROID_PYRAMID) + { + // start at edge midpoint + vMidID[0] = MidID(1,i/2); + + // there are 2 scvf per edge + if(i%2 == 0){ + vMidID[1] = MidID(2, rRefElem.id(1, i/2, 2, 0)); // side 0 + vMidID[2] = MidID(dim, 0); // center of element + } else { + vMidID[1] = MidID(dim, 0); // center of element + vMidID[2] = MidID(2, rRefElem.id(1, i/2, 2, 1)); // side 1 + } + } +// octahedron here (analogue to scvf ordering in pyramids but in top/bottom pairs) + else if(rRefElem.roid() == ROID_OCTAHEDRON) + { + switch (i) + { + // scvf of edge 4 (top) + case 0: vMidID[0] = MidID(1,4); // edge 4 + vMidID[1] = MidID(2,8); // subface 0 = 1,2,3 + vMidID[2] = MidID(3,1); // subvolume 0 + vMidID[3] = MidID(2,4); // face 4 + break; + // scvf of edge 4 (bottom) + case 1: vMidID[0] = MidID(1,4); // edge 4 + vMidID[1] = MidID(2,9); // subface 1 = 1,3,2 + vMidID[2] = MidID(3,3); // subvolume 2 + vMidID[3] = MidID(2,0); // face 0 + break; + + + // scvf of edge 5 (top) + case 2: vMidID[0] = MidID(1,5); // edge 5 + vMidID[1] = MidID(2,8); // subface 0 = 1,2,3 + vMidID[2] = MidID(3,1); // subvolume 0 + vMidID[3] = MidID(2,5); // face 5 + break; + // scvf of edge 5 (bottom) + case 3: vMidID[0] = MidID(1,5); // edge 5 + vMidID[1] = MidID(2,9); // subface 1 = 1,3,2 + vMidID[2] = MidID(3,3); // subvolume 2 + vMidID[3] = MidID(2,1); // face 1 + break; + + + // scvf of diagonal 3->1 (top) in subvolume 0 + case 4: vMidID[0] = MidID(1,12);// diagonal 3->1 + vMidID[1] = MidID(2,8); // subface 0 = 1,2,3 + vMidID[2] = MidID(3,1); // subvolume 0 + vMidID[3] = MidID(2,13);// face 1,5,3 + break; + // scvf of diagonal 1->3 (bottom) in subvolume 2 + case 5: vMidID[0] = MidID(1,13);// diagonal 1->3 + vMidID[1] = MidID(2,9); // subface 1 = 1,3,2 + vMidID[2] = MidID(3,3); // subvolume 2 + vMidID[3] = MidID(2,14);// face 1,0,3 + break; + + + // scvf of edge 8 in subvolume 0 + case 6: vMidID[0] = MidID(1,8); // edge 8 + vMidID[1] = MidID(2,4); // face 4 + vMidID[2] = MidID(3,1); // subvolume 0 + vMidID[3] = MidID(2,13);// face 1,5,3 + break; + // scvf of edge 0 in subvolume 2 + case 7: vMidID[0] = MidID(1,0); // edge 0 + vMidID[1] = MidID(2,15);// face 1,3,0 + vMidID[2] = MidID(3,3); // subvolume 2 + vMidID[3] = MidID(2,0); // face 0 + break; + + + // scvf of edge 9 + case 8: vMidID[0] = MidID(1,9); // edge 9 + vMidID[1] = MidID(2,5); // face 5 + vMidID[2] = MidID(3,1); // subvolume 0 + vMidID[3] = MidID(2,4); // face 4 + break; + // scvf of edge 1 + case 9: vMidID[0] = MidID(1,1); // edge 1 + vMidID[1] = MidID(2,0); // face 0 + vMidID[2] = MidID(3,3); // subvolume 2 + vMidID[3] = MidID(2,1); // face 1 + break; + + + // scvf of edge 10 in subvolume 0 + case 10:vMidID[0] = MidID(1,10);// edge 10 + vMidID[1] = MidID(2,12);// face 1,3,5 + vMidID[2] = MidID(3,1); // subvolume 0 + vMidID[3] = MidID(2,5); // face 5 + break; + // scvf of edge 2 in subvolume 2 + case 11:vMidID[0] = MidID(1,2); // edge 2 + vMidID[1] = MidID(2,1); // face 1 + vMidID[2] = MidID(3,3); // subvolume 2 + vMidID[3] = MidID(2,14);// face 1,0,3 + break; + + + // scvf of diagonal 1->3 (top) in subvolume 1 + case 12:vMidID[0] = MidID(1,13);// diagonal 1->3 + vMidID[1] = MidID(2,10);// subface 2 = 1,3,4 + vMidID[2] = MidID(3,2); // subvolume 1 + vMidID[3] = MidID(2,12);// face 1,3,5 + break; + // scvf of diagonal 3->1 (bottom) in subvolume 3 + case 13:vMidID[0] = MidID(1,12);// diagonal 3->1 + vMidID[1] = MidID(2,11);// subface 3 = 1,4,3 + vMidID[2] = MidID(3,4); // subvolume 3 + vMidID[3] = MidID(2,15);// face 1,3,0 + break; + + + // scvf of edge 6 (top) + case 14:vMidID[0] = MidID(1,6); // edge 6 + vMidID[1] = MidID(2,10);// subface 2 = 1,3,4 + vMidID[2] = MidID(3,2); // subvolume 1 + vMidID[3] = MidID(2,6); // face 6 + break; + // scvf of edge 6 (bottom) + case 15:vMidID[0] = MidID(1,6); // edge 6 + vMidID[1] = MidID(2,11);// subface 3 = 1,4,3 + vMidID[2] = MidID(3,4); // subvolume 3 + vMidID[3] = MidID(2,2); // face 2 + break; + + + // scvf of edge 7 (top) + case 16:vMidID[0] = MidID(1,7); // edge 7 + vMidID[1] = MidID(2,10);// subface 2 = 1,3,4 + vMidID[2] = MidID(3,2); // subvolume 1 + vMidID[3] = MidID(2,7); // face 7 + break; + // scvf of edge 7 (bottom) + case 17:vMidID[0] = MidID(1,7); // edge 7 + vMidID[1] = MidID(2,11);// subface 3 = 1,4,3 + vMidID[2] = MidID(3,4); // subvolume 3 + vMidID[3] = MidID(2,3); // face 3 + break; + + + // scvf of edge 8 in subvolume 1 + case 18:vMidID[0] = MidID(1,8); // edge 8 + vMidID[1] = MidID(2,13);// face 1,5,3 + vMidID[2] = MidID(3,2); // subvolume 1 + vMidID[3] = MidID(2,7); // face 7 + break; + // scvf of edge 0 in subvolume 3 + case 19:vMidID[0] = MidID(1,0); // edge 0 + vMidID[1] = MidID(2,3); // face 3 + vMidID[2] = MidID(3,4); // subvolume 3 + vMidID[3] = MidID(2,15);// face 1,3,0 + break; + + + // scvf of edge 10 in subvolume 1 + case 20:vMidID[0] = MidID(1,10);// edge 10 + vMidID[1] = MidID(2,6); // face 6 + vMidID[2] = MidID(3,2); // subvolume 1 + vMidID[3] = MidID(2,12);// face 1,3,5 + break; + // scvf of edge 2 in subvolume 3 + case 21:vMidID[0] = MidID(1,2); // edge 2 + vMidID[1] = MidID(2,14);// face 1,0,3 + vMidID[2] = MidID(3,4); // subvolume 3 + vMidID[3] = MidID(2,2); // face 2 + break; + + + // scvf of edge 11 in subvolume 1 + case 22:vMidID[0] = MidID(1,11);// edge 11 + vMidID[1] = MidID(2,7); // face 7 + vMidID[2] = MidID(3,2); // subvolume 1 + vMidID[3] = MidID(2,6); // face 6 + break; + // scvf of edge 3 in subvolume 3 + case 23:vMidID[0] = MidID(1,3); // edge 3 + vMidID[1] = MidID(2,2); // face 2 + vMidID[2] = MidID(3,4); // subvolume 3 + vMidID[3] = MidID(2,3); // face 3 + break; + + + default:UG_THROW("Octahedron only has 24 SCVFs (no. 0-23), but requested no. " << i << "."); + break; + } + } +} + +/** + * \param[in] i indicates that scv corresponds to i'th corner of ref elem + */ +template +static void ComputeSCVMidID(const TRefElem& rRefElem, + MidID vMidID[], int i) +{ + static const int dim = TRefElem::dim; + + if (rRefElem.roid() != ROID_PYRAMID && rRefElem.roid() != ROID_OCTAHEDRON) + { + if(dim == 1) + { + vMidID[0] = MidID(0, i); // set node as corner of scv + vMidID[1] = MidID(dim, 0); // center of element + } + else if(dim == 2) + { + vMidID[0] = MidID(0, i); // set node as corner of scv + vMidID[1] = MidID(1, rRefElem.id(0, i, 1, 0)); // edge 1 + vMidID[2] = MidID(dim, 0); // center of element + vMidID[3] = MidID(1, rRefElem.id(0, i, 1, 1)); // edge 2 + } + else if(dim == 3) + { + vMidID[0] = MidID(0, i); // set node as corner of scv + vMidID[1] = MidID(1, rRefElem.id(0, i, 1, 1)); // edge 1 + vMidID[2] = MidID(2, rRefElem.id(0, i, 2, 0)); // face 0 + vMidID[3] = MidID(1, rRefElem.id(0, i, 1, 0)); // edge 0 + vMidID[4] = MidID(1, rRefElem.id(0, i, 1, 2)); // edge 2 + vMidID[5] = MidID(2, rRefElem.id(0, i, 2, 2)); // face 2 + vMidID[6] = MidID(dim, 0); // center of element + vMidID[7] = MidID(2, rRefElem.id(0, i, 2, 1)); // face 1 + } + else {UG_THROW("Dimension higher than 3 not implemented.");} + } +// pyramid here + else if (rRefElem.roid() == ROID_PYRAMID) + { + // start at edge midpoint + vMidID[3] = MidID(1,i/4); + + // there are 2 scvf per edge + if(i%4 == 0 || i%4 == 1){ + vMidID[1] = MidID(2, rRefElem.id(1, i/4, 2, 0)); // side 0 + vMidID[2] = MidID(dim, 0); // center of element + } else { + vMidID[1] = MidID(dim, 0); // center of element + vMidID[2] = MidID(2, rRefElem.id(1, i/4, 2, 1)); // side 1 + } + + // connect to from / to corners of edge + if(i%2 == 0){ + vMidID[0] = MidID(0, rRefElem.id(1, i/4, 0, 0)); // from + } else { + vMidID[0] = MidID(0, rRefElem.id(1, i/4, 0, 1)); // to + } + } + // octahedron here (analogue to scv ordering in pyramids but in top/bottom pairs) + else if(rRefElem.roid() == ROID_OCTAHEDRON) + { + switch (i) + { + // scv of corner 1 in subvolume 0 (top) + case 0: vMidID[0] = MidID(0,1); // corner 1 + vMidID[1] = MidID(1,4); // edge 4 + vMidID[2] = MidID(2,8); // subface 0 = 1,2,3 + vMidID[3] = MidID(1,12);// edge 3->1 + vMidID[4] = MidID(1,8); // edge 8 + vMidID[5] = MidID(2,4); // face 4 + vMidID[6] = MidID(3,1); // subvolume 0 + vMidID[7] = MidID(2,13);// face 1,5,3 + break; + // scv of corner 1 in subvolume 2 (bottom) + case 1: vMidID[0] = MidID(0,1); // corner 1 + vMidID[1] = MidID(1,13);// edge 1->3 + vMidID[2] = MidID(2,9); // subface 1 = 1,3,2 + vMidID[3] = MidID(1,4); // edge 4 + vMidID[4] = MidID(1,0); // edge 0 + vMidID[5] = MidID(2,15);// face 1,3,0 + vMidID[6] = MidID(3,3); // subvolume 2 + vMidID[7] = MidID(2,0); // face 0 + break; + + + // scv of corner 2 in subvolume 0 (top) + case 2: vMidID[0] = MidID(0,2); // corner 2 + vMidID[1] = MidID(1,5); // edge 5 + vMidID[2] = MidID(2,8); // subface 0 = 1,2,3 + vMidID[3] = MidID(1,4); // edge 4 + vMidID[4] = MidID(1,9); // edge 9 + vMidID[5] = MidID(2,5); // face 5 + vMidID[6] = MidID(3,1); // subvolume 0 + vMidID[7] = MidID(2,4); // face 4 + break; + // scv of corner 2 in subvolume 2 (bottom) + case 3: vMidID[0] = MidID(0,2); // corner 2 + vMidID[1] = MidID(1,4); // edge 4 + vMidID[2] = MidID(2,9); // subface 1 = 1,3,2 + vMidID[3] = MidID(1,5); // edge 5 + vMidID[4] = MidID(1,1); // edge 1 + vMidID[5] = MidID(2,0); // face 0 + vMidID[6] = MidID(3,3); // subvolume 2 + vMidID[7] = MidID(2,1); // face 1 + break; + + + // scv of corner 3 in subvolume 0 (top) + case 4: vMidID[0] = MidID(0,3); // corner 3 + vMidID[1] = MidID(1,12);// edge 3->1 + vMidID[2] = MidID(2,8); // subface 0 = 1,2,3 + vMidID[3] = MidID(1,5); // edge 5 + vMidID[4] = MidID(1,10);// edge 10 + vMidID[5] = MidID(2,13);// face 1,5,3 + vMidID[6] = MidID(3,1); // subvolume 0 + vMidID[7] = MidID(2,5); // face 5 + break; + // scv of corner 3 in subvolume 2 (bottom) + case 5: vMidID[0] = MidID(0,3); // corner 3 + vMidID[1] = MidID(1,5); // edge 5 + vMidID[2] = MidID(2,9); // subface 0 = 1,3,2 + vMidID[3] = MidID(1,13);// edge 1->3 + vMidID[4] = MidID(1,2); // edge 2 + vMidID[5] = MidID(2,1); // face 1 + vMidID[6] = MidID(3,3); // subvolume 2 + vMidID[7] = MidID(2,15);// face 1,3,0 + break; + + + // scv of corner 5 in subvolume 0 (top) + case 6: vMidID[0] = MidID(0,5); // corner 5 + vMidID[1] = MidID(1,9); // edge 9 + vMidID[2] = MidID(2,4); // face 4 + vMidID[3] = MidID(1,8); // edge 8 + vMidID[4] = MidID(1,10);// edge 10 + vMidID[5] = MidID(2,5); // face 5 + vMidID[6] = MidID(3,1); // subvolume 0 + vMidID[7] = MidID(2,13);// subface 1,5,3 + break; + // scv of corner 0 in subvolume 2 (bottom) + case 7: vMidID[0] = MidID(0,0); // corner 0 + vMidID[1] = MidID(1,0); // edge 0 + vMidID[2] = MidID(2,0); // face 0 + vMidID[3] = MidID(1,1); // edge 1 + vMidID[4] = MidID(1,2); // edge 2 + vMidID[5] = MidID(2,14);// subface 1,0,3 + vMidID[6] = MidID(3,3); // subvolume 2 + vMidID[7] = MidID(2,1); // face 1 + break; + + + // scv of corner 1 in subvolume 1 (top) + case 8: vMidID[0] = MidID(0,1); // corner 1 + vMidID[1] = MidID(1,13);// edge 1->3 + vMidID[2] = MidID(2,10);// subface 2 = 1,3,4 + vMidID[3] = MidID(1,7); // edge 7 + vMidID[4] = MidID(1,8); // edge 8 + vMidID[5] = MidID(2,12);// face 1,3,5 + vMidID[6] = MidID(3,2); // subvolume 1 + vMidID[7] = MidID(2,7); // face 7 + break; + // scv of corner 1 in subvolume 3 (bottom) + case 9: vMidID[0] = MidID(0,1); // corner 1 + vMidID[1] = MidID(1,7); // edge 7 + vMidID[2] = MidID(2,11);// subface 3 = 1,4,3 + vMidID[3] = MidID(1,12);// edge 3->1 + vMidID[4] = MidID(1,0); // edge 0 + vMidID[5] = MidID(2,3); // face 3 + vMidID[6] = MidID(3,4); // subvolume 3 + vMidID[7] = MidID(2,14);// face 1,0,3 + break; + + + // scv of corner 3 in subvolume 1 (top) + case 10:vMidID[0] = MidID(0,3); // corner 3 + vMidID[1] = MidID(1,6); // edge 6 + vMidID[2] = MidID(2,10);// subface 2 = 1,3,4 + vMidID[3] = MidID(1,13);// edge 1->3 + vMidID[4] = MidID(1,10);// edge 10 + vMidID[5] = MidID(2,6); // face 6 + vMidID[6] = MidID(3,2); // subvolume 1 + vMidID[7] = MidID(2,12);// face 1,3,5 + break; + // scv of corner 3 in subvolume 3 (bottom) + case 11:vMidID[0] = MidID(0,3); // corner 3 + vMidID[1] = MidID(1,12);// edge 3->1 + vMidID[2] = MidID(2,11);// subface 3 = 1,4,3 + vMidID[3] = MidID(1,6); // edge 6 + vMidID[4] = MidID(1,2); // edge 2 + vMidID[5] = MidID(2,14);// face 1,0,3 + vMidID[6] = MidID(3,4); // subvolume 3 + vMidID[7] = MidID(2,2); // face 2 + break; + + + // scv of corner 4 in subvolume 1 (top) + case 12:vMidID[0] = MidID(0,4); // corner 4 + vMidID[1] = MidID(1,7); // edge 7 + vMidID[2] = MidID(2,10);// subface 2 = 1,3,4 + vMidID[3] = MidID(1,6); // edge 6 + vMidID[4] = MidID(1,11);// edge 11 + vMidID[5] = MidID(2,7); // face 7 + vMidID[6] = MidID(3,2); // subvolume 1 + vMidID[7] = MidID(2,6); // face 6 + break; + // scv of corner 4 in subvolume 3 (bottom) + case 13:vMidID[0] = MidID(0,4); // corner 4 + vMidID[1] = MidID(1,6); // edge 6 + vMidID[2] = MidID(2,11);// subface 3 = 1,4,3 + vMidID[3] = MidID(1,7); // edge 7 + vMidID[4] = MidID(1,3); // edge 3 + vMidID[5] = MidID(2,2); // face 2 + vMidID[6] = MidID(3,4); // subvolume 3 + vMidID[7] = MidID(2,3); // face 3 + break; + + + // scv of corner 5 in subvolume 1 (top) + case 14:vMidID[0] = MidID(0,5); // corner 5 + vMidID[1] = MidID(1,10);// edge 10 + vMidID[2] = MidID(2,12);// subface 1,3,5 + vMidID[3] = MidID(1,8); // edge 8 + vMidID[4] = MidID(1,11);// edge 11 + vMidID[5] = MidID(2,6); // face 6 + vMidID[6] = MidID(3,2); // subvolume 1 + vMidID[7] = MidID(2,7); // face 7 + break; + // scv of corner 0 in subvolume 3 (bottom) + case 15:vMidID[0] = MidID(0,0); // corner 0 + vMidID[1] = MidID(1,0); // edge 0 + vMidID[2] = MidID(2,15);// subface 1,3,0 + vMidID[3] = MidID(1,2); // edge 2 + vMidID[4] = MidID(1,3); // edge 3 + vMidID[5] = MidID(2,3); // face 3 + vMidID[6] = MidID(3,4); // subvolume 3 + vMidID[7] = MidID(2,2); // face 2 + break; + default:UG_THROW("Octahedron only has 16 SCVs (no. 0-15), but requested no. " << i << "."); + break; + } + } +} + +/** + * \param[in] i indicates that bf corresponds to i'th corner of ref elem + */ +template +static void ComputeBFMidID(const TRefElem& rRefElem, int side, + MidID vMidID[], int co) +{ + static const int dim = TRefElem::dim; + + // number of corners of side + const int coOfSide = rRefElem.num(dim-1, side, 0); + + // set mid ids + if (dim == 1) + { + vMidID[0] = MidID(0, rRefElem.id(0, side, 0, co)); + } + else if(dim == 2) + { + vMidID[co%2] = MidID(0, rRefElem.id(1, side, 0, co)); // corner of side + vMidID[(co+1)%2] = MidID(1, side); // side midpoint + } + else if (dim == 3) + { + vMidID[0] = MidID(0, rRefElem.id(2, side, 0, co)); // corner of side + vMidID[1] = MidID(1, rRefElem.id(2, side, 1, co)); // edge co + vMidID[2] = MidID(2, side); // side midpoint + vMidID[3] = MidID(1, rRefElem.id(2, side, 1, (co -1 + coOfSide)%coOfSide)); // edge co-1 + } +} + +template +static void CopyCornerByMidID(MathVector vCorner[], + const MidID vMidID[], + MathVector vvMidPos[][maxMid], + const size_t numCo) +{ + for(size_t i = 0; i < numCo; ++i) + { + const size_t d = vMidID[i].dim; + const size_t id = vMidID[i].id; + vCorner[i] = vvMidPos[d][id]; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// FV1FT Geometry for Reference Element Type +//////////////////////////////////////////////////////////////////////////////// + +template +FV1FTGeometry:: +FV1FTGeometry() + : m_pElem(NULL), m_rRefElem(Provider::get()), + m_rTrialSpace(Provider::get()) +{ + update_local_data(); +} + +template +void FV1FTGeometry:: +update_local_data() +{ + +// set corners of element as local centers of nodes + for(size_t i = 0; i < m_rRefElem.num(0); ++i) + m_vvLocMid[0][i] = m_rRefElem.corner(i); + +// compute local midpoints + ComputeMidPoints(m_rRefElem, m_vvLocMid[0], m_vvLocMid); + +// set up local information for SubControlVolumeFaces (scvf) + for(size_t i = 0; i < num_scvf(); ++i) + { + + // this scvf separates the given nodes + if (m_rRefElem.REFERENCE_OBJECT_ID != ROID_PYRAMID && m_rRefElem.REFERENCE_OBJECT_ID != ROID_OCTAHEDRON) + { + m_vSCVF[i].From = m_rRefElem.id(1, i, 0, 0); + m_vSCVF[i].To = m_rRefElem.id(1, i, 0, 1); + } + // special case pyramid + else if(m_rRefElem.REFERENCE_OBJECT_ID == ROID_PYRAMID) + { + // map according to order defined in ComputeSCVFMidID + m_vSCVF[i].From = m_rRefElem.id(1, i/2, 0, 0); + m_vSCVF[i].To = m_rRefElem.id(1, i/2, 0, 1); + } + // special case octahedron (scvf not mappable by edges) + else if(m_rRefElem.REFERENCE_OBJECT_ID == ROID_OCTAHEDRON) + { + // map according to order defined in ComputeSCVFMidID + switch(i) + { + case 0: m_vSCVF[i].From = 1; + m_vSCVF[i].To = 2; + break; + case 1: m_vSCVF[i].From = 2; + m_vSCVF[i].To = 1; + break; + + + case 2: m_vSCVF[i].From = 2; + m_vSCVF[i].To = 3; + break; + case 3: m_vSCVF[i].From = 3; + m_vSCVF[i].To = 2; + break; + + + case 4: m_vSCVF[i].From = 3; + m_vSCVF[i].To = 1; + break; + case 5: m_vSCVF[i].From = 1; + m_vSCVF[i].To = 3; + break; + + + case 6: m_vSCVF[i].From = 1; + m_vSCVF[i].To = 5; + break; + case 7: m_vSCVF[i].From = 1; + m_vSCVF[i].To = 0; + break; + + + case 8: m_vSCVF[i].From = 2; + m_vSCVF[i].To = 5; + break; + case 9: m_vSCVF[i].From = 2; + m_vSCVF[i].To = 0; + break; + + + case 10:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 5; + break; + case 11:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 0; + break; + + + case 12:m_vSCVF[i].From = 1; + m_vSCVF[i].To = 3; + break; + case 13:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 1; + break; + + + case 14:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 4; + break; + case 15:m_vSCVF[i].From = 4; + m_vSCVF[i].To = 3; + break; + + + case 16:m_vSCVF[i].From = 4; + m_vSCVF[i].To = 1; + break; + case 17:m_vSCVF[i].From = 1; + m_vSCVF[i].To = 4; + break; + + + case 18:m_vSCVF[i].From = 1; + m_vSCVF[i].To = 5; + break; + case 19:m_vSCVF[i].From = 1; + m_vSCVF[i].To = 0; + break; + + + case 20:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 5; + break; + case 21:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 0; + break; + + + case 22:m_vSCVF[i].From = 4; + m_vSCVF[i].To = 5; + break; + case 23:m_vSCVF[i].From = 4; + m_vSCVF[i].To = 0; + break; + } + } + + // compute mid ids of the scvf + ComputeSCVFMidID(m_rRefElem, m_vSCVF[i].vMidID, i); + + // copy local corners of scvf + CopyCornerByMidID(m_vSCVF[i].vLocPos, m_vSCVF[i].vMidID, m_vvLocMid, SCVF::numCo); + + // integration point + AveragePositions(m_vSCVF[i].localIP, m_vSCVF[i].vLocPos, SCVF::numCo); + } + +// set up local informations for SubControlVolumes (scv) +// each scv is associated to one corner of the element + for(size_t i = 0; i < num_scv(); ++i) + { + // store associated node + if (m_rRefElem.REFERENCE_OBJECT_ID != ROID_PYRAMID && m_rRefElem.REFERENCE_OBJECT_ID != ROID_OCTAHEDRON) + { + m_vSCV[i].nodeId = i; + } + // special case pyramid + else if(m_rRefElem.REFERENCE_OBJECT_ID == ROID_PYRAMID) + { + // map according to order defined in ComputeSCVMidID + if(i%2 == 0){ + m_vSCV[i].nodeId = m_rRefElem.id(1, i/4, 0, 0); // from + } else { + m_vSCV[i].nodeId = m_rRefElem.id(1, i/4, 0, 1); // to + } + } + // special case octahedron (scvf not mappable by edges) + else if(m_rRefElem.REFERENCE_OBJECT_ID == ROID_OCTAHEDRON) + { + // map according to order defined in ComputeSCVMidID + switch(i) + { + case 0: m_vSCV[i].nodeId = 1; + break; + case 1: m_vSCV[i].nodeId = 1; + break; + + + case 2: m_vSCV[i].nodeId = 2; + break; + case 3: m_vSCV[i].nodeId = 2; + break; + + + case 4: m_vSCV[i].nodeId = 3; + break; + case 5: m_vSCV[i].nodeId = 3; + break; + + + case 6: m_vSCV[i].nodeId = 5; + break; + case 7: m_vSCV[i].nodeId = 0; + break; + + + case 8: m_vSCV[i].nodeId = 1; + break; + case 9: m_vSCV[i].nodeId = 1; + break; + + + case 10:m_vSCV[i].nodeId = 3; + break; + case 11:m_vSCV[i].nodeId = 3; + break; + + + case 12:m_vSCV[i].nodeId = 4; + break; + case 13:m_vSCV[i].nodeId = 4; + break; + + + case 14:m_vSCV[i].nodeId = 5; + break; + case 15:m_vSCV[i].nodeId = 0; + break; + } + } + + // compute mid ids scv + ComputeSCVMidID(m_rRefElem, m_vSCV[i].midId, i); + + // copy local corners of scv + CopyCornerByMidID(m_vSCV[i].vLocPos, m_vSCV[i].midId, m_vvLocMid, m_vSCV[i].num_corners()); + } + +// compute Shapes and Derivatives + for(size_t i = 0; i < num_scvf(); ++i) + { + m_rTrialSpace.shapes(&(m_vSCVF[i].vShape[0]), m_vSCVF[i].local_ip()); + m_rTrialSpace.grads(&(m_vSCVF[i].vLocalGrad[0]), m_vSCVF[i].local_ip()); + } + + for(size_t i = 0; i < num_scv(); ++i) + { + m_rTrialSpace.shapes(&(m_vSCV[i].vShape[0]), m_vSCV[i].local_ip()); + m_rTrialSpace.grads(&(m_vSCV[i].vLocalGrad[0]), m_vSCV[i].local_ip()); + } + +// copy ip positions in a list for Sub Control Volumes Faces (SCVF) + for(size_t i = 0; i < num_scvf(); ++i) + m_vLocSCVF_IP[i] = scvf(i).local_ip(); + + if(ref_elem_type::REFERENCE_OBJECT_ID == ROID_PYRAMID || ref_elem_type::REFERENCE_OBJECT_ID == ROID_OCTAHEDRON) + for(size_t i = 0; i < num_scv(); ++i) + m_vLocSCV_IP[i] = scv(i).local_ip(); +} + +/// update data for given element +template +void FV1FTGeometry:: +update(GridObject* elem, const MathVector* vCornerCoords, const ISubsetHandler* ish) +{ + UG_ASSERT(dynamic_cast(elem) != NULL, "Wrong element type."); + TElem* pElem = static_cast(elem); + +// if already update for this element, do nothing + if(m_pElem == pElem) return; else m_pElem = pElem; + +// remember global position of nodes + for(size_t i = 0; i < m_rRefElem.num(0); ++i) + m_vvGloMid[0][i] = vCornerCoords[i]; + +// compute global midpoints + ComputeMidPoints(m_rRefElem, m_vvGloMid[0], m_vvGloMid); + + +// compute global informations for scvf + for(size_t i = 0; i < num_scvf(); ++i) + { + // copy local corners of scvf + CopyCornerByMidID(m_vSCVF[i].vGloPos, m_vSCVF[i].vMidID, m_vvGloMid, SCVF::numCo); + + // integration point + AveragePositions(m_vSCVF[i].globalIP, m_vSCVF[i].vGloPos, SCVF::numCo); + + // normal on scvf + traits::NormalOnSCVF(m_vSCVF[i].Normal, m_vSCVF[i].vGloPos, m_vvGloMid[0]); + } + +// compute size of scv + for(size_t i = 0; i < num_scv(); ++i) + { + // copy global corners + CopyCornerByMidID(m_vSCV[i].vGloPos, m_vSCV[i].midId, m_vvGloMid, m_vSCV[i].num_corners()); + + // compute volume of scv + m_vSCV[i].Vol = ElementSize(m_vSCV[i].vGloPos); + + /* + * Only for debug purposes testing octahedral FV1 discretization + * + MathVector baryCenter(0.0); + for(size_t j = 0; j < 8; ++j) + { + baryCenter += m_vSCV[i].vLocPos[j]; + } + + baryCenter *= 1.0/8.0; + * + */ + + } + +// Shapes and Derivatives + m_mapping.update(vCornerCoords); + +// if mapping is linear, compute jacobian only once and copy + if(ReferenceMapping::isLinear) + { + MathMatrix JtInv; + m_mapping.jacobian_transposed_inverse(JtInv, m_vSCVF[0].local_ip()); + const number detJ = m_mapping.sqrt_gram_det(m_vSCVF[0].local_ip()); + + for(size_t i = 0; i < num_scvf(); ++i) + { + m_vSCVF[i].JtInv = JtInv; + m_vSCVF[i].detj = detJ; + } + + for(size_t i = 0; i < num_scv(); ++i) + { + m_vSCV[i].JtInv = JtInv; + m_vSCV[i].detj = detJ; + } + } +// else compute jacobian for each integration point + else + { + for(size_t i = 0; i < num_scvf(); ++i) + { + m_mapping.jacobian_transposed_inverse(m_vSCVF[i].JtInv, m_vSCVF[i].local_ip()); + m_vSCVF[i].detj = m_mapping.sqrt_gram_det(m_vSCVF[i].local_ip()); + } + for(size_t i = 0; i < num_scv(); ++i) + { + m_mapping.jacobian_transposed_inverse(m_vSCV[i].JtInv, m_vSCV[i].local_ip()); + m_vSCV[i].detj = m_mapping.sqrt_gram_det(m_vSCV[i].local_ip()); + } + } + +// compute global gradients + for(size_t i = 0; i < num_scvf(); ++i) + for(size_t sh = 0 ; sh < scvf(i).num_sh(); ++sh) + MatVecMult(m_vSCVF[i].vGlobalGrad[sh], m_vSCVF[i].JtInv, m_vSCVF[i].vLocalGrad[sh]); + + for(size_t i = 0; i < num_scv(); ++i) + for(size_t sh = 0 ; sh < scv(i).num_sh(); ++sh) + MatVecMult(m_vSCV[i].vGlobalGrad[sh], m_vSCV[i].JtInv, m_vSCV[i].vLocalGrad[sh]); + +// Copy ip pos in list for SCVF + for(size_t i = 0; i < num_scvf(); ++i) + m_vGlobSCVF_IP[i] = scvf(i).global_ip(); + + if(ref_elem_type::REFERENCE_OBJECT_ID == ROID_PYRAMID || ref_elem_type::REFERENCE_OBJECT_ID == ROID_OCTAHEDRON) + for(size_t i = 0; i < num_scv(); ++i) + m_vGlobSCV_IP[i] = scv(i).global_ip(); + +// if no boundary subsets required, return + if(num_boundary_subsets() == 0 || ish == NULL) return; + else update_boundary_faces(pElem, vCornerCoords, ish); +} + +template +void FV1FTGeometry:: +update_boundary_faces(GridObject* elem, const MathVector* vCornerCoords, const ISubsetHandler* ish) +{ + UG_ASSERT(dynamic_cast(elem) != NULL, "Wrong element type."); + TElem* pElem = static_cast(elem); + +// get grid + Grid& grid = *(ish->grid()); + +// vector of subset indices of side + std::vector vSubsetIndex; + +// get subset indices for sides (i.e. edge in 2d, faces in 3d) + if(dim == 1) { + std::vector vVertex; + CollectVertices(vVertex, grid, pElem); + vSubsetIndex.resize(vVertex.size()); + for(size_t i = 0; i < vVertex.size(); ++i) + vSubsetIndex[i] = ish->get_subset_index(vVertex[i]); + } + if(dim == 2) { + std::vector vEdges; + CollectEdgesSorted(vEdges, grid, pElem); + vSubsetIndex.resize(vEdges.size()); + for(size_t i = 0; i < vEdges.size(); ++i) + vSubsetIndex[i] = ish->get_subset_index(vEdges[i]); + } + if(dim == 3) { + std::vector vFaces; + CollectFacesSorted(vFaces, grid, pElem); + vSubsetIndex.resize(vFaces.size()); + for(size_t i = 0; i < vFaces.size(); ++i) + vSubsetIndex[i] = ish->get_subset_index(vFaces[i]); + } + +// loop requested subset + typename std::map >::iterator it; + for (it=m_mapVectorBF.begin() ; it != m_mapVectorBF.end(); ++it) + { + // get subset index + const int bndIndex = (*it).first; + + // get vector of BF for element + std::vector& vBF = (*it).second; + + // clear vector + vBF.clear(); + + // current number of bf + size_t curr_bf = 0; + + // loop sides of element + for(size_t side = 0; side < vSubsetIndex.size(); ++side) + { + // skip non boundary sides + if(vSubsetIndex[side] != bndIndex) continue; + + // number of corners of side + const int coOfSide = m_rRefElem.num(dim-1, side, 0); + + // resize vector + vBF.resize(curr_bf + coOfSide); + + // loop corners + for(int co = 0; co < coOfSide; ++co) + { + // get current bf + BF& bf = vBF[curr_bf]; + + // set node id == scv this bf belongs to + bf.nodeId = m_rRefElem.id(dim-1, side, 0, co); + + // Compute MidID for BF + ComputeBFMidID(m_rRefElem, side, bf.vMidID, co); + + // copy corners of bf + CopyCornerByMidID(bf.vLocPos, bf.vMidID, m_vvLocMid, BF::numCo); + CopyCornerByMidID(bf.vGloPos, bf.vMidID, m_vvGloMid, BF::numCo); + + // integration point + AveragePositions(bf.localIP, bf.vLocPos, BF::numCo); + AveragePositions(bf.globalIP, bf.vGloPos, BF::numCo); + + // normal on scvf + traits::NormalOnBF(bf.Normal, bf.vGloPos, m_vvGloMid[0]); + + // compute volume + bf.Vol = VecTwoNorm(bf.Normal); + + m_rTrialSpace.shapes(&(bf.vShape[0]), bf.localIP); + m_rTrialSpace.grads(&(bf.vLocalGrad[0]), bf.localIP); + + m_mapping.jacobian_transposed_inverse(bf.JtInv, bf.localIP); + bf.detj = m_mapping.sqrt_gram_det(bf.localIP); + + for(size_t sh = 0 ; sh < bf.num_sh(); ++sh) + MatVecMult(bf.vGlobalGrad[sh], bf.JtInv, bf.vLocalGrad[sh]); + + // increase curr_bf + ++curr_bf; + } + } + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Dim-dependent Finite Volume Geometry +//////////////////////////////////////////////////////////////////////////////// +template +void DimFV1FTGeometry:: +update_local(ReferenceObjectID roid) +{ + m_roid = roid; + +// get reference element + try + { + const DimReferenceElement& rRefElem + = ReferenceElementProvider::get(m_roid); + + // set corners of element as local centers of nodes + for(size_t i = 0; i < rRefElem.num(0); ++i) + m_vvLocMid[0][i] = rRefElem.corner(i); + + // compute local midpoints + ComputeMidPoints, maxMid> + (rRefElem, m_vvLocMid[0], m_vvLocMid); + + // set number of scvf / scv of this roid + if(m_roid != ROID_PYRAMID && m_roid != ROID_OCTAHEDRON) + { + m_numSCV = rRefElem.num(0); + m_numSCVF = rRefElem.num(1); + } + else if(dim == 3 && m_roid == ROID_PYRAMID) + { + UG_WARNING("Pyramid Finite Volume Geometry for 1st order currently " + "implemented in DimFV1Geom EXPERIMENTATLLY. Please contact " + "Martin Stepniewski or Andreas Vogel if you see this message.") + + m_numSCV = 4*rRefElem.num(1); + m_numSCVF = 2*rRefElem.num(1); + } + else if(dim == 3 && m_roid == ROID_OCTAHEDRON) + { + // Case octahedron + m_numSCV = 16; + m_numSCVF = 24; + } + + // set up local informations for SubControlVolumeFaces (scvf) + // each scvf is associated to one edge of the element + for(size_t i = 0; i < num_scvf(); ++i) + { + // this scvf separates the given nodes + if (m_roid != ROID_PYRAMID && m_roid != ROID_OCTAHEDRON) + { + m_vSCVF[i].From = rRefElem.id(1, i, 0, 0); + m_vSCVF[i].To = rRefElem.id(1, i, 0, 1); + } + // special case pyramid (scvf not mappable by edges) + else if (dim == 3 && m_roid == ROID_PYRAMID) + { + // map according to order defined in ComputeSCVFMidID + m_vSCVF[i].From = rRefElem.id(1, i/2, 0, 0); + m_vSCVF[i].To = rRefElem.id(1, i/2, 0, 1); + } + // special case octahedron (scvf not mappable by edges) + else if(dim == 3 && m_roid == ROID_OCTAHEDRON) + { + // map according to order defined in ComputeSCVFMidID + switch(i) + { + case 0: m_vSCVF[i].From = 1; + m_vSCVF[i].To = 2; + break; + case 1: m_vSCVF[i].From = 2; + m_vSCVF[i].To = 1; + break; + + + case 2: m_vSCVF[i].From = 2; + m_vSCVF[i].To = 3; + break; + case 3: m_vSCVF[i].From = 3; + m_vSCVF[i].To = 2; + break; + + + case 4: m_vSCVF[i].From = 3; + m_vSCVF[i].To = 1; + break; + case 5: m_vSCVF[i].From = 1; + m_vSCVF[i].To = 3; + break; + + + case 6: m_vSCVF[i].From = 1; + m_vSCVF[i].To = 5; + break; + case 7: m_vSCVF[i].From = 1; + m_vSCVF[i].To = 0; + break; + + + case 8: m_vSCVF[i].From = 2; + m_vSCVF[i].To = 5; + break; + case 9: m_vSCVF[i].From = 2; + m_vSCVF[i].To = 0; + break; + + + case 10:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 5; + break; + case 11:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 0; + break; + + + case 12:m_vSCVF[i].From = 1; + m_vSCVF[i].To = 3; + break; + case 13:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 1; + break; + + + case 14:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 4; + break; + case 15:m_vSCVF[i].From = 4; + m_vSCVF[i].To = 3; + break; + + + case 16:m_vSCVF[i].From = 4; + m_vSCVF[i].To = 1; + break; + case 17:m_vSCVF[i].From = 1; + m_vSCVF[i].To = 4; + break; + + + case 18:m_vSCVF[i].From = 1; + m_vSCVF[i].To = 5; + break; + case 19:m_vSCVF[i].From = 1; + m_vSCVF[i].To = 0; + break; + + + case 20:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 5; + break; + case 21:m_vSCVF[i].From = 3; + m_vSCVF[i].To = 0; + break; + + + case 22:m_vSCVF[i].From = 4; + m_vSCVF[i].To = 5; + break; + case 23:m_vSCVF[i].From = 4; + m_vSCVF[i].To = 0; + break; + } + } + + + // compute mid ids of the scvf + ComputeSCVFMidID(rRefElem, m_vSCVF[i].vMidID, i); + + // copy local corners of scvf + CopyCornerByMidID(m_vSCVF[i].vLocPos, m_vSCVF[i].vMidID, m_vvLocMid, SCVF::numCo); + + // integration point + AveragePositions(m_vSCVF[i].localIP, m_vSCVF[i].vLocPos, SCVF::numCo); + } + + // set up local informations for SubControlVolumes (scv) + // each scv is associated to one corner of the element + for(size_t i = 0; i < num_scv(); ++i) + { + // store associated node + if (m_roid != ROID_PYRAMID && m_roid != ROID_OCTAHEDRON) + { + m_vSCV[i].nodeId = i; + } + // special case pyramid (scv not mappable by corners) + else if(dim == 3 && m_roid == ROID_PYRAMID) + { + // map according to order defined in ComputeSCVMidID + if(i%2 == 0){ + m_vSCV[i].nodeId = rRefElem.id(1, i/4, 0, 0); // from + } else { + m_vSCV[i].nodeId = rRefElem.id(1, i/4, 0, 1); // to + } + } + // special case octahedron (scvf not mappable by edges) + else if(dim == 3 && m_roid == ROID_OCTAHEDRON) + { + // map according to order defined in ComputeSCVMidID + switch(i) + { + case 0: m_vSCV[i].nodeId = 1; + break; + case 1: m_vSCV[i].nodeId = 1; + break; + + + case 2: m_vSCV[i].nodeId = 2; + break; + case 3: m_vSCV[i].nodeId = 2; + break; + + + case 4: m_vSCV[i].nodeId = 3; + break; + case 5: m_vSCV[i].nodeId = 3; + break; + + + case 6: m_vSCV[i].nodeId = 5; + break; + case 7: m_vSCV[i].nodeId = 0; + break; + + + case 8: m_vSCV[i].nodeId = 1; + break; + case 9: m_vSCV[i].nodeId = 1; + break; + + + case 10:m_vSCV[i].nodeId = 3; + break; + case 11:m_vSCV[i].nodeId = 3; + break; + + + case 12:m_vSCV[i].nodeId = 4; + break; + case 13:m_vSCV[i].nodeId = 4; + break; + + + case 14:m_vSCV[i].nodeId = 5; + break; + case 15:m_vSCV[i].nodeId = 0; + break; + } + } + + // compute mid ids scv + ComputeSCVMidID(rRefElem, m_vSCV[i].vMidID, i); + + // copy local corners of scv + CopyCornerByMidID(m_vSCV[i].vLocPos, m_vSCV[i].vMidID, m_vvLocMid, m_vSCV[i].num_corners()); + } + + ///////////////////////// + // Shapes and Derivatives + ///////////////////////// + + const LocalShapeFunctionSet& TrialSpace = + LocalFiniteElementProvider::get(m_roid, LFEID(LFEID::LAGRANGE, dim, 1)); + + m_nsh = TrialSpace.num_sh(); + + for(size_t i = 0; i < num_scvf(); ++i) + { + m_vSCVF[i].numSH = TrialSpace.num_sh(); + TrialSpace.shapes(&(m_vSCVF[i].vShape[0]), m_vSCVF[i].localIP); + TrialSpace.grads(&(m_vSCVF[i].vLocalGrad[0]), m_vSCVF[i].localIP); + } + + for(size_t i = 0; i < num_scv(); ++i) + { + m_vSCV[i].numSH = TrialSpace.num_sh(); + TrialSpace.shapes(&(m_vSCV[i].vShape[0]), m_vSCV[i].vLocPos[0]); + TrialSpace.grads(&(m_vSCV[i].vLocalGrad[0]), m_vSCV[i].vLocPos[0]); + } + + } + UG_CATCH_THROW("DimFV1FTGeometry: update failed."); + +// copy ip positions in a list for Sub Control Volumes Faces (SCVF) + for(size_t i = 0; i < num_scvf(); ++i) + m_vLocSCVF_IP[i] = scvf(i).local_ip(); + + if(roid == ROID_PYRAMID || roid == ROID_OCTAHEDRON) + for(size_t i = 0; i < num_scv(); ++i) + m_vLocSCV_IP[i] = scv(i).local_ip(); +} + + +/// update data for given element +template +void DimFV1FTGeometry:: +update(GridObject* pElem, const MathVector* vCornerCoords, const ISubsetHandler* ish) +{ + +/////////////////////////////////////////////////////////////////////////////////// +// (1) - (4= pre-processing for re-computing the cooridnates of element +// corners 'vCornerCoords' in case of a cut element + + set_element_modus(false); + +// If already update for this element, do nothing + if(m_pElem == pElem) return; else m_pElem = pElem; + +// (1) collect potentially new 'vCornerCoords' and set the elemModus +// (INSIDE_DOM/OUTSIDE_DOM/CUT_BY_INTERFACE) + bool do_update_local = false; + try{ + do_update_local = m_spInterfaceHandler->update_elem(pElem, vCornerCoords); + } + UG_CATCH_THROW("DimFV1FTGeometry: access to InterfaceHander::update_elem() failed!."); + + +// (2) If OUTSIDE_DOM: set m_roid to usual value and perform local update + if( m_spInterfaceHandler->elementModus() == OUTSIDE_DOM) + { + if ( dim == 2 ) m_roid = ROID_TRIANGLE; + if ( dim == 3 ) m_roid = ROID_TETRAHEDRON; + + update_local(m_roid); + } + +// (3) get computed roid and perform the local update based on that + if (do_update_local || m_roid != m_spInterfaceHandler->roid() ) + { + if( m_spInterfaceHandler->elementModus() != OUTSIDE_DOM ) + { + m_roid = m_spInterfaceHandler->roid(); + update_local(m_roid); + } + } + +// (4) set needed flag + if(m_spInterfaceHandler->elementModus() == CUT_BY_INTERFACE) + set_element_modus(true); + + +////////////////////////////////////////////////////////////////////////////////////// +// now: perform usual computations on potentially updated cut element 'vCornerCoords' + +// get reference element + try{ + const DimReferenceElement& rRefElem + = ReferenceElementProvider::get(m_roid); + +// remember global position of nodes + for(size_t i = 0; i < rRefElem.num(0); ++i) + m_vvGloMid[0][i] = m_spInterfaceHandler->corner(i); + + +// compute local midpoints + ComputeMidPoints, maxMid>(rRefElem, m_vvGloMid[0], m_vvGloMid); + +// compute global informations for scvf + for(size_t i = 0; i < num_scvf(); ++i) + { + // copy local corners of scvf + CopyCornerByMidID(m_vSCVF[i].vGloPos, m_vSCVF[i].vMidID, m_vvGloMid, SCVF::numCo); + + // integration point + AveragePositions(m_vSCVF[i].globalIP, m_vSCVF[i].vGloPos, SCVF::numCo); + + // normal on scvf + traits::NormalOnSCVF(m_vSCVF[i].Normal, m_vSCVF[i].vGloPos, m_vvGloMid[0]); + } + +// compute size of scv + for(size_t i = 0; i < num_scv(); ++i) + { + // copy global corners + CopyCornerByMidID(m_vSCV[i].vGloPos, m_vSCV[i].vMidID, m_vvGloMid, m_vSCV[i].num_corners()); + + // compute volume of scv + m_vSCV[i].Vol = ElementSize(m_vSCV[i].vGloPos); + } + +// get reference mapping + DimReferenceMapping& rMapping = ReferenceMappingProvider::get(m_roid); + rMapping.update(m_spInterfaceHandler->corners()); + //rMapping.update(vCornerCoords); + + + //\todo compute with on virt. call +// compute jacobian for linear mapping + if(rMapping.is_linear()) + { + MathMatrix JtInv; + rMapping.jacobian_transposed_inverse(JtInv, m_vSCVF[0].local_ip()); + const number detJ = rMapping.sqrt_gram_det(m_vSCVF[0].local_ip()); + + for(size_t i = 0; i < num_scvf(); ++i) + { + m_vSCVF[i].JtInv = JtInv; + m_vSCVF[i].detj = detJ; + } + + for(size_t i = 0; i < num_scv(); ++i) + { + m_vSCV[i].JtInv = JtInv; + m_vSCV[i].detj = detJ; + } + } +// else compute jacobian for each integration point + else + { + for(size_t i = 0; i < num_scvf(); ++i) + { + rMapping.jacobian_transposed_inverse(m_vSCVF[i].JtInv, m_vSCVF[i].local_ip()); + m_vSCVF[i].detj = rMapping.sqrt_gram_det(m_vSCVF[i].local_ip()); + } + for(size_t i = 0; i < num_scv(); ++i) + { + rMapping.jacobian_transposed_inverse(m_vSCV[i].JtInv, m_vSCV[i].local_ip()); + m_vSCV[i].detj = rMapping.sqrt_gram_det(m_vSCV[i].local_ip()); + } + } + +// compute global gradients + for(size_t i = 0; i < num_scvf(); ++i) + for(size_t sh = 0; sh < scvf(i).num_sh(); ++sh) + MatVecMult(m_vSCVF[i].vGlobalGrad[sh], m_vSCVF[i].JtInv, m_vSCVF[i].vLocalGrad[sh]); + + for(size_t i = 0; i < num_scv(); ++i) + for(size_t sh = 0; sh < scv(i).num_sh(); ++sh) + MatVecMult(m_vSCV[i].vGlobalGrad[sh], m_vSCV[i].JtInv, m_vSCV[i].vLocalGrad[sh]); + +// copy ip points in list (SCVF) + for(size_t i = 0; i < num_scvf(); ++i) + m_vGlobSCVF_IP[i] = scvf(i).global_ip(); + + if(m_roid == ROID_PYRAMID || m_roid == ROID_OCTAHEDRON) + for(size_t i = 0; i < num_scv(); ++i) + m_vGlobSCV_IP[i] = scv(i).global_ip(); + + } + UG_CATCH_THROW("DimFV1FTGeometry: update failed."); + + +///////////////////////////////////////////////////////////////////////////// +// compute boundary faces of inner boundary: m_vBF-data +// --> needed for assembling boundary-conditions on immersed interface + if(m_spInterfaceHandler->elementModus() == CUT_BY_INTERFACE) + { + update_inner_boundary_faces(); + m_spInterfaceHandler->update_inner_boundary(vCornerCoords); + + } + else if(m_spInterfaceHandler->elementModus() == CUT_BY_2_INTERFACE) + { + if ( m_spInterfaceHandler->StdFV_assembling() ) + { + update_inner_boundary_faces(); + m_spInterfaceHandler->update_inner_boundary_for2(); + } + else + { + update_inner_boundary_faces_for2(); + m_spInterfaceHandler->update_inner_boundary_for2(); + } + } + + + +// if no boundary subsets required, return + if(num_boundary_subsets() == 0 || ish == NULL) return; + else update_boundary_faces(pElem, vCornerCoords, ish); +} + + + +// compare implementation of 'DimFV1Geometry::update_boundary_faces()' +template +void DimFV1FTGeometry:: +update_inner_boundary_faces() +{ + ///////////////////////////////////////////////////////////////////////////// + // get general data + ///////////////////////////////////////////////////////////////////////////// + try{ + const DimReferenceElement& rRefElem + = ReferenceElementProvider::get(m_roid); + + DimReferenceMapping& rMapping = ReferenceMappingProvider::get(m_roid); + rMapping.update(m_spInterfaceHandler->corners()); + + const LocalShapeFunctionSet& TrialSpace = + LocalFiniteElementProvider::get(m_roid, LFEID(LFEID::LAGRANGE, dim, 1)); + + ///////////////////////////////////////////////////////////////////////////// + // collect boudary faces + ///////////////////////////////////////////////////////////////////////////// + + // get number of sides of element + size_t numSides = 0; + numSides = rRefElem.num(dim-1); + + // current number of bf + size_t curr_bf = 0; + + // std::vector& vBF = m_spInterfaceHandler->m_vBF; + std::vector& vBF = m_spInterfaceHandler->get_boundary_faces(); + + vBF.clear(); + + // loop sides of element + for(size_t side = 0; side < numSides; ++side) + { + // side is no boundary face => continue + if( m_spInterfaceHandler->elementModus() == CUT_BY_2_INTERFACE) + { + if ( !m_spInterfaceHandler->is_boundary_face_for2(side) ) + continue; + } + else + { + if ( !m_spInterfaceHandler->is_boundary_face(side) ) + continue; + } + // number of corners of side (special case bottom side pyramid) + const int coOfSide = (m_roid != ROID_PYRAMID || side != 0) + ? rRefElem.num(dim-1, side, 0) : rRefElem.num(dim-1, side, 0) + 2; + + // resize vector + vBF.resize(curr_bf + coOfSide); + + // loop corners + for(int co = 0; co < coOfSide; ++co) + { + // get current bf + BF& bf = vBF[curr_bf]; + + // set node id == scv this bf belongs to + if (m_roid != ROID_PYRAMID || side != 0){ + bf.nodeId = rRefElem.id(dim-1, side, 0, co); + } + else + { + // map according to order defined in ComputeBFMidID + bf.nodeId = rRefElem.id(dim-1, side, 0, (co % 3) + (co>3 ? 1 : 0)); + } + + // Compute MidID for BF + ComputeBFMidID(rRefElem, side, bf.vMidID, co); + + // copy corners of bf + CopyCornerByMidID(bf.vLocPos, bf.vMidID, m_vvLocMid, BF::numCo); + CopyCornerByMidID(bf.vGloPos, bf.vMidID, m_vvGloMid, BF::numCo); + + // integration point + AveragePositions(bf.localIP, bf.vLocPos, BF::numCo); + AveragePositions(bf.globalIP, bf.vGloPos, BF::numCo); + + // normal on scvf + traits::NormalOnBF(bf.Normal, bf.vGloPos, m_vvGloMid[0]); + + // compute volume + bf.Vol = VecTwoNorm(bf.Normal); + + // compute shapes and grads + bf.numSH = TrialSpace.num_sh(); + TrialSpace.shapes(&(bf.vShape[0]), bf.localIP); + TrialSpace.grads(&(bf.vLocalGrad[0]), bf.localIP); + + // get reference mapping + rMapping.jacobian_transposed_inverse(bf.JtInv, bf.localIP); + bf.detj = rMapping.sqrt_gram_det(bf.localIP); + + // compute global gradients + for(size_t sh = 0 ; sh < bf.num_sh(); ++sh) + MatVecMult(bf.vGlobalGrad[sh], bf.JtInv, bf.vLocalGrad[sh]); + + // increase curr_bf + ++curr_bf; + + } // end loop of corners of side + + } // end loop sides of element + + } + UG_CATCH_THROW("DimFV1FTGeometry: update_inner_boundary() failed."); + + +} + +// compare implementation of 'DimFV1Geometry::update_boundary_faces()' +template +void DimFV1FTGeometry:: +update_inner_boundary_faces_for2() +{ + for ( size_t i = 0; i < 4; ++i ) + //UG_LOG("m_spInterfaceHandler->quadriCorners()[" << i << "]: " << m_spInterfaceHandler->quadriCorners()[i] << "\n"); + + ///////////////////////////////////////////////////////////////////////////// + // get general data + ///////////////////////////////////////////////////////////////////////////// + try{ + const DimReferenceElement& rRefElem + = ReferenceElementProvider::get(ROID_QUADRILATERAL); + + DimReferenceMapping& rMapping = ReferenceMappingProvider::get(ROID_QUADRILATERAL); + rMapping.update(m_spInterfaceHandler->quadriCorners()); + + const LocalShapeFunctionSet& TrialSpace = + LocalFiniteElementProvider::get(ROID_QUADRILATERAL, LFEID(LFEID::LAGRANGE, dim, 1)); + + MathVector buffer_vvLocMid[dim+1][maxMid]; + // set corners of element as local centers of nodes + for(size_t i = 0; i < rRefElem.num(0); ++i) + { + buffer_vvLocMid[0][i] = rRefElem.corner(i); + UG_LOG("**** buffer_vvLocMid[0][" << i << "]: " << buffer_vvLocMid[0][i] << "\n"); + + } + // compute local midpoints + ComputeMidPoints, maxMid> + (rRefElem, buffer_vvLocMid[0], buffer_vvLocMid); + + MathVector buffer_vvGloMid[dim+1][maxMid]; + // remember global position of nodes + for(size_t i = 0; i < rRefElem.num(0); ++i) + { + buffer_vvGloMid[0][i] = m_spInterfaceHandler->quadriCorners()[i]; + UG_LOG("**** buffer_vvGloMid[0][" << i << "]: " << buffer_vvGloMid[0][i] << "\n"); + } + // compute local midpoints + ComputeMidPoints, maxMid>(rRefElem, buffer_vvGloMid[0], buffer_vvGloMid); + + + ///////////////////////////////////////////////////////////////////////////// + // collect boudary faces + ///////////////////////////////////////////////////////////////////////////// + + // get number of sides of element + size_t numSides = 0; + numSides = rRefElem.num(dim-1); + + // current number of bf + size_t curr_bf = 0; + + std::vector& vBF = m_spInterfaceHandler->get_boundary_faces(); + + vBF.clear(); + // loop sides of element + for(size_t side = 0; side < numSides; ++side) + { + // side is no boundary face => continue + if ( side == 1 || side == 3 ) + continue; + + // number of corners of side (special case bottom side pyramid) + const int coOfSide = (ROID_QUADRILATERAL != ROID_PYRAMID || side != 0) + ? rRefElem.num(dim-1, side, 0) : rRefElem.num(dim-1, side, 0) + 2; + + // resize vector + vBF.resize(curr_bf + coOfSide); + + // loop corners + for(int co = 0; co < coOfSide; ++co) + { + // get current bf + BF& bf = vBF[curr_bf]; + + // set nodeID to ID of corner within the Triangle used for assembling the fluid node equation: + bf.nodeId = curr_bf; //m_spInterfaceHandler->m_vQuadriOrigID[curr_bf]; //rRefElem.id(dim-1, side, 0, co); + + // Compute MidID for BF + ComputeBFMidID(rRefElem, side, bf.vMidID, co); + + // copy corners of bf + CopyCornerByMidID(bf.vLocPos, bf.vMidID, buffer_vvLocMid, BF::numCo); + CopyCornerByMidID(bf.vGloPos, bf.vMidID, buffer_vvGloMid, BF::numCo); + + // integration point + AveragePositions(bf.localIP, bf.vLocPos, BF::numCo); + AveragePositions(bf.globalIP, bf.vGloPos, BF::numCo); + + // normal on scvf + traits::NormalOnBF(bf.Normal, bf.vGloPos, buffer_vvGloMid[0]); + + UG_LOG("BF::numCo " << BF::numCo << "\n"); + UG_LOG("co = " << co << ": bf.vGloPos[0]: " << bf.vGloPos[0] << "\n"); + UG_LOG("co = " << co << ": bf.vGloPos[1]: " << bf.vGloPos[1] << "\n"); + UG_LOG("bf.Normal:" << bf.Normal << "\n"); + UG_LOG("bf.nodeID:" << bf.nodeId << "\n"); + + // compute volume + bf.Vol = VecTwoNorm(bf.Normal); + + // compute shapes and grads + bf.numSH = TrialSpace.num_sh(); + TrialSpace.shapes(&(bf.vShape[0]), bf.localIP); + TrialSpace.grads(&(bf.vLocalGrad[0]), bf.localIP); + + // get reference mapping + rMapping.jacobian_transposed_inverse(bf.JtInv, bf.localIP); + bf.detj = rMapping.sqrt_gram_det(bf.localIP); + + // compute global gradients + for(size_t sh = 0 ; sh < bf.num_sh(); ++sh) + MatVecMult(bf.vGlobalGrad[sh], bf.JtInv, bf.vLocalGrad[sh]); + + // increase curr_bf + ++curr_bf; + + } // end loop of corners of side + + } // end loop sides of element + + } + UG_CATCH_THROW("DimFV1FTGeometry: update_inner_boundary() failed."); + +} + + +template +void DimFV1FTGeometry:: +update_boundary_faces(GridObject* pElem, const MathVector* vCornerCoords, const ISubsetHandler* ish) +{ +// get grid + Grid& grid = *(ish->grid()); + +// vector of subset indices of side + std::vector vSubsetIndex; + +// get subset indices for sides (i.e. edge in 2d, faces in 3d) + if(dim == 1) { + std::vector vVertex; + CollectVertices(vVertex, grid, pElem); + vSubsetIndex.resize(vVertex.size()); + for(size_t i = 0; i < vVertex.size(); ++i) + vSubsetIndex[i] = ish->get_subset_index(vVertex[i]); + } + if(dim == 2) { + std::vector vEdges; + CollectEdgesSorted(vEdges, grid, pElem); + vSubsetIndex.resize(vEdges.size()); + for(size_t i = 0; i < vEdges.size(); ++i) + vSubsetIndex[i] = ish->get_subset_index(vEdges[i]); + } + if(dim == 3) { + std::vector vFaces; + CollectFacesSorted(vFaces, grid, pElem); + vSubsetIndex.resize(vFaces.size()); + for(size_t i = 0; i < vFaces.size(); ++i) + vSubsetIndex[i] = ish->get_subset_index(vFaces[i]); + } + + try{ + const DimReferenceElement& rRefElem + = ReferenceElementProvider::get(m_roid); + + DimReferenceMapping& rMapping = ReferenceMappingProvider::get(m_roid); + rMapping.update(vCornerCoords); + + const LocalShapeFunctionSet& TrialSpace = + LocalFiniteElementProvider::get(m_roid, LFEID(LFEID::LAGRANGE, dim, 1)); + +// loop requested subset + typename std::map >::iterator it; + for (it=m_mapVectorBF.begin() ; it != m_mapVectorBF.end(); ++it) + { + // get subset index + const int bndIndex = (*it).first; + + // get vector of BF for element + std::vector& vBF = (*it).second; + + // clear vector + vBF.clear(); + + // current number of bf + size_t curr_bf = 0; + + // loop sides of element + for(size_t side = 0; side < vSubsetIndex.size(); ++side) + { + // skip non boundary sides + if(vSubsetIndex[side] != bndIndex) continue; + + // number of corners of side + const int coOfSide = rRefElem.num(dim-1, side, 0); + + // resize vector + vBF.resize(curr_bf + coOfSide); + + // loop corners + for(int co = 0; co < coOfSide; ++co) + { + // get current bf + BF& bf = vBF[curr_bf]; + + // set node id == scv this bf belongs to + bf.nodeId = rRefElem.id(dim-1, side, 0, co); + + // Compute MidID for BF + ComputeBFMidID(rRefElem, side, bf.vMidID, co); + + // copy corners of bf + CopyCornerByMidID(bf.vLocPos, bf.vMidID, m_vvLocMid, BF::numCo); + CopyCornerByMidID(bf.vGloPos, bf.vMidID, m_vvGloMid, BF::numCo); + + // integration point + AveragePositions(bf.localIP, bf.vLocPos, BF::numCo); + AveragePositions(bf.globalIP, bf.vGloPos, BF::numCo); + + // normal on scvf + traits::NormalOnBF(bf.Normal, bf.vGloPos, m_vvGloMid[0]); + + // compute volume + bf.Vol = VecTwoNorm(bf.Normal); + + // compute shapes and grads + bf.numSH = TrialSpace.num_sh(); + TrialSpace.shapes(&(bf.vShape[0]), bf.localIP); + TrialSpace.grads(&(bf.vLocalGrad[0]), bf.localIP); + + // get reference mapping + rMapping.jacobian_transposed_inverse(bf.JtInv, bf.localIP); + bf.detj = rMapping.sqrt_gram_det(bf.localIP); + + // compute global gradients + for(size_t sh = 0 ; sh < bf.num_sh(); ++sh) + MatVecMult(bf.vGlobalGrad[sh], bf.JtInv, bf.vLocalGrad[sh]); + + // increase curr_bf + ++curr_bf; + } + } + } + + } + UG_CATCH_THROW("DimFV1FTGeometry: update failed."); +} + +////////////////////// +// FV1FTGeometry + +template class FV1FTGeometry; +template class FV1FTGeometry; +template class FV1FTGeometry; + +template class FV1FTGeometry; +template class FV1FTGeometry; + +template class FV1FTGeometry; +template class FV1FTGeometry; + +template class FV1FTGeometry; +template class FV1FTGeometry; +template class FV1FTGeometry; +template class FV1FTGeometry; +template class FV1FTGeometry; + +////////////////////// +// DimFV1FTGeometry +template class DimFV1FTGeometry<1, 1, InterfaceHandlerLocalParticle<1> >; + +template class DimFV1FTGeometry<2, 2, InterfaceHandlerLocalParticle<2> >; + +template class DimFV1FTGeometry<3, 3, InterfaceHandlerLocalParticle<3> >; + + +} // end namespace ug + +#endif /* __H__UG__LIB_DISC__SPATIAL_DISC__DISC_HELPER__FV1FT_GEOMETRY_IMPL_ */ diff --git a/ugbase/lib_disc/spatial_disc/disc_util/fv1ib_geom.h b/ugbase/lib_disc/spatial_disc/disc_util/fv1FT_geom.h similarity index 52% rename from ugbase/lib_disc/spatial_disc/disc_util/fv1ib_geom.h rename to ugbase/lib_disc/spatial_disc/disc_util/fv1FT_geom.h index 0c8b3005b..0cce6c2d6 100644 --- a/ugbase/lib_disc/spatial_disc/disc_util/fv1ib_geom.h +++ b/ugbase/lib_disc/spatial_disc/disc_util/fv1FT_geom.h @@ -1,6 +1,6 @@ /* - * Copyright (c) 2014-2015: G-CSC, Goethe University Frankfurt - * Author: Susanne Höllbacher + * Copyright (c) 2010-2015: G-CSC, Goethe University Frankfurt + * Author: Andreas Vogel * * This file is part of UG4. * @@ -30,8 +30,8 @@ * GNU Lesser General Public License for more details. */ -#ifndef FV1IB_GEOM_H_ -#define FV1IB_GEOM_H_ +#ifndef __H__UG__LIB_DISC__SPATIAL_DISC__DISC_HELPER__FV1FT_GEOMETRY__ +#define __H__UG__LIB_DISC__SPATIAL_DISC__DISC_HELPER__FV1FT_GEOMETRY__ // extern libraries #include @@ -53,10 +53,15 @@ #include "fv_util.h" #include "fv_geom_base.h" -namespace ug{ +#include "lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_flat_top_cut/interface_handler_particle.h" +namespace ug{ + +//template +//class InterfaceHandlerLocalParticle; + //////////////////////////////////////////////////////////////////////////////// -// FV1 Geometry for Reference Element Type +// FV1FT Geometry for Reference Element Type //////////////////////////////////////////////////////////////////////////////// /// Geometry and shape functions for 1st order Vertex-Centered Finite Volume @@ -65,408 +70,402 @@ namespace ug{ * \tparam TWorldDim (physical) world dimension */ template < typename TElem, int TWorldDim> -class FV1IBGeometry : public FVGeometryBase +class FV1FTGeometry : public FVGeometryBase { -public: -/// type of element - typedef TElem elem_type; - -/// type of reference element - typedef typename reference_element_traits::reference_element_type ref_elem_type; + public: + /// type of element + typedef TElem elem_type; -/// used traits - typedef fv1_traits traits; + /// type of reference element + typedef typename reference_element_traits::reference_element_type ref_elem_type; -public: -/// dimension of reference element - static const int dim = ref_elem_type::dim; + /// used traits + typedef fv1_traits traits; -/// dimension of world - static const int worldDim = TWorldDim; + public: + /// dimension of reference element + static const int dim = ref_elem_type::dim; -/// Hanging node flag: this Geometry does not support hanging nodes - static const bool usesHangingNodes = false; + /// dimension of world + static const int worldDim = TWorldDim; -/// flag indicating if local data may change - static const bool staticLocalData = true; + /// Hanging node flag: this Geometry does not support hanging nodes + static const bool usesHangingNodes = false; -public: -/// order - static const int order = 1; + /// flag indicating if local data may change + static const bool staticLocalData = true; -/// number of SubControlVolumes - static const size_t numSCV = (ref_elem_type::REFERENCE_OBJECT_ID != ROID_PYRAMID) - ? ref_elem_type::numCorners : 8; + public: + /// order + static const int order = 1; -/// type of SubControlVolume - typedef typename traits::scv_type scv_type; + /// number of SubControlVolumes + static const size_t numSCV = (ref_elem_type::REFERENCE_OBJECT_ID == ROID_PYRAMID || ref_elem_type::REFERENCE_OBJECT_ID == ROID_OCTAHEDRON) + ? ((ref_elem_type::REFERENCE_OBJECT_ID == ROID_PYRAMID) ? (4*ref_elem_type::numEdges) : 16) : ref_elem_type::numCorners; -/// number of SubControlVolumeFaces - static const size_t numSCVF = (ref_elem_type::REFERENCE_OBJECT_ID != ROID_PYRAMID) - ? ref_elem_type::numEdges : 12; + /// type of SubControlVolume + typedef typename traits::scv_type scv_type; -/// type of Shape function used - typedef LagrangeP1 local_shape_fct_set_type; + /// number of SubControlVolumeFaces + static const size_t numSCVF = (ref_elem_type::REFERENCE_OBJECT_ID == ROID_PYRAMID || ref_elem_type::REFERENCE_OBJECT_ID == ROID_OCTAHEDRON) + ? ((ref_elem_type::REFERENCE_OBJECT_ID == ROID_PYRAMID) ? (2*ref_elem_type::numEdges) : 24) : ref_elem_type::numEdges; -/// number of shape functions - static const size_t nsh = local_shape_fct_set_type::nsh; + /// type of Shape function used + typedef LagrangeP1 local_shape_fct_set_type; -/// number of integration points - static const size_t nip = 1; + /// number of shape functions + static const size_t nsh = local_shape_fct_set_type::nsh; -public: -/// Sub-Control Volume Face structure -/** - * Each finite element is cut by several sub-control volume faces. The idea - * is that the "dual" skeleton formed by the sub control volume faces of - * all elements again gives rise to a regular mesh with closed - * (lipschitz-bounded) control volumes. The SCVF are the boundary of the - * control volume. In computation the flux over each SCVF must be the same - * in both directions over the face in order to guarantee the conservation - * property. - */ - class SCVF - { - public: - /// Number of corners of scvf - static const size_t numCo = traits::NumCornersOfSCVF; + /// number of integration points + static const size_t nip = 1; - public: - SCVF() {} + public: + /// Sub-Control Volume Face structure + /** + * Each finite element is cut by several sub-control volume faces. The idea + * is that the "dual" skeleton formed by the sub control volume faces of + * all elements again gives rise to a regular mesh with closed + * (lipschitz-bounded) control volumes. The SCVF are the boundary of the + * control volume. In computation the flux over each SCVF must be the same + * in both directions over the face in order to guarantee the conservation + * property. + */ + class SCVF + { + public: + /// Number of corners of scvf + static const size_t numCo = traits::NumCornersOfSCVF; - /// index of SubControlVolume on one side of the scvf - inline size_t from() const {return From;} + public: + SCVF() {} - /// index of SubControlVolume on one side of the scvf - inline size_t to() const {return To;} + /// index of SubControlVolume on one side of the scvf + inline size_t from() const {return From;} - /// normal on scvf (points direction "from"->"to"). Norm is equal to area - inline const MathVector& normal() const {return Normal;} + /// index of SubControlVolume on one side of the scvf + inline size_t to() const {return To;} - /// number of integration points on scvf - inline size_t num_ip() const {return nip;} + /// normal on scvf (points direction "from"->"to"). Norm is equal to area + inline const MathVector& normal() const {return Normal;} - /// local integration point of scvf - inline const MathVector& local_ip() const {return localIP;} + /// number of integration points on scvf + inline size_t num_ip() const {return nip;} - /// global integration point of scvf - inline const MathVector& global_ip() const {return globalIP;} + /// local integration point of scvf + inline const MathVector& local_ip() const {return localIP;} - /// Transposed Inverse of Jacobian in integration point - inline const MathMatrix& JTInv() const {return JtInv;} + /// global integration point of scvf + inline const MathVector& global_ip() const {return globalIP;} - /// Determinant of Jacobian in integration point - inline number detJ() const {return detj;} + /// Transposed Inverse of Jacobian in integration point + inline const MathMatrix& JTInv() const {return JtInv;} - /// number of shape functions - inline size_t num_sh() const {return nsh;} + /// Determinant of Jacobian in integration point + inline number detJ() const {return detj;} - /// value of shape function i in integration point - inline number shape(size_t sh) const {return vShape[sh];} + /// number of shape functions + inline size_t num_sh() const {return nsh;} - /// vector of shape functions in ip point - inline const number* shape_vector() const {return vShape;} + /// value of shape function i in integration point + inline number shape(size_t sh) const {return vShape[sh];} - /// value of local gradient of shape function i in integration point - inline const MathVector& local_grad(size_t sh) const - {UG_ASSERT(sh < num_sh(), "Invalid index"); return vLocalGrad[sh];} + /// vector of shape functions in ip point + inline const number* shape_vector() const {return vShape;} - /// vector of local gradients in ip point - inline const MathVector* local_grad_vector() const {return vLocalGrad;} + /// value of local gradient of shape function i in integration point + inline const MathVector& local_grad(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vLocalGrad[sh];} - /// value of global gradient of shape function i in integration point - inline const MathVector& global_grad(size_t sh) const - {UG_ASSERT(sh < num_sh(), "Invalid index"); return vGlobalGrad[sh];} + /// vector of local gradients in ip point + inline const MathVector* local_grad_vector() const {return vLocalGrad;} - /// vector of global gradients in ip point - inline const MathVector* global_grad_vector() const {return vGlobalGrad;} + /// value of global gradient of shape function i in integration point + inline const MathVector& global_grad(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vGlobalGrad[sh];} - /// number of corners, that bound the scvf - inline size_t num_corners() const {return numCo;} + /// vector of global gradients in ip point + inline const MathVector* global_grad_vector() const {return vGlobalGrad;} - /// return local corner number i - inline const MathVector& local_corner(size_t co) const - {UG_ASSERT(co < num_corners(), "Invalid index."); return vLocPos[co];} + /// number of corners, that bound the scvf + inline size_t num_corners() const {return numCo;} - /// return global corner number i - inline const MathVector& global_corner(size_t co) const - {UG_ASSERT(co < num_corners(), "Invalid index."); return vGloPos[co];} + /// return local corner number i + inline const MathVector& local_corner(size_t co) const + {UG_ASSERT(co < num_corners(), "Invalid index."); return vLocPos[co];} - protected: - // let outer class access private members - friend class FV1IBGeometry; + /// return global corner number i + inline const MathVector& global_corner(size_t co) const + {UG_ASSERT(co < num_corners(), "Invalid index."); return vGloPos[co];} - // This scvf separates the scv with the ids given in "from" and "to" - // The computed normal points in direction from->to - size_t From, To; + private: + // let outer class access private members + friend class FV1FTGeometry; - // The normal on the SCVF pointing (from -> to) - MathVector Normal; // normal (incl. area) + // This scvf separates the scv with the ids given in "from" and "to" + // The computed normal points in direction from->to + size_t From, To; - // ordering is: - // 1D: edgeMidPoint - // 2D: edgeMidPoint, CenterOfElement - // 3D: edgeMidPoint, Side one, CenterOfElement, Side two - MathVector vLocPos[numCo]; // local corners of scvf - MathVector vGloPos[numCo]; // global corners of scvf - MidID vMidID[numCo]; // dimension and id of object, that's midpoint bounds the scvf + // The normal on the SCVF pointing (from -> to) + MathVector Normal; // normal (incl. area) - // scvf part - MathVector localIP; // local integration point - MathVector globalIP; // global integration point + // ordering is: + // 1D: edgeMidPoint + // 2D: edgeMidPoint, CenterOfElement + // 3D: edgeMidPoint, Side one, CenterOfElement, Side two + MathVector vLocPos[numCo]; // local corners of scvf + MathVector vGloPos[numCo]; // global corners of scvf + MidID vMidID[numCo]; // dimension and id of object, that's midpoint bounds the scvf - // shapes and derivatives - number vShape[nsh]; // shapes at ip - MathVector vLocalGrad[nsh]; // local grad at ip - MathVector vGlobalGrad[nsh]; // global grad at ip - MathMatrix JtInv; // Jacobian transposed at ip - number detj; // Jacobian det at ip - }; + // scvf part + MathVector localIP; // local integration point + MathVector globalIP; // global integration point -/// sub control volume structure - class SCV - { - public: - /// Number of corners of scvf - static const size_t numCo = traits::NumCornersOfSCV; + // shapes and derivatives + number vShape[nsh]; // shapes at ip + MathVector vLocalGrad[nsh]; // local grad at ip + MathVector vGlobalGrad[nsh]; // global grad at ip + MathMatrix JtInv; // Jacobian transposed at ip + number detj; // Jacobian det at ip + }; - public: - SCV() {}; + /// sub control volume structure + class SCV + { + public: + /// Number of corners of scvf + static const size_t numCo = traits::NumCornersOfSCV; - /// volume of scv - inline number volume() const {return Vol;} + public: + SCV() {}; - /// number of corners, that bound the scvf - inline size_t num_corners() const {return numCo;} + /// volume of scv + inline number volume() const {return Vol;} - /// return local corner number i - inline const MathVector& local_corner(size_t co) const - {UG_ASSERT(co < num_corners(), "Invalid index."); return vLocPos[co];} + /// number of corners, that bound the scvf + inline size_t num_corners() const {return numCo;} - /// return global corner number i - inline const MathVector& global_corner(size_t co) const - {UG_ASSERT(co < num_corners(), "Invalid index."); return vGloPos[co];} + /// return local corner number i + inline const MathVector& local_corner(size_t co) const + {UG_ASSERT(co < num_corners(), "Invalid index."); return vLocPos[co];} - /// return local corners - inline const MathVector* local_corners() const - {return &vLocPos[0];} + /// return global corner number i + inline const MathVector& global_corner(size_t co) const + {UG_ASSERT(co < num_corners(), "Invalid index."); return vGloPos[co];} - /// return global corners - inline const MathVector* global_corners() const - {return &vGloPos[0];} + /// return local corners + inline const MathVector* local_corners() const + {return &vLocPos[0];} - /// node id that this scv is associated to - inline size_t node_id() const {return nodeId;} + /// return global corners + inline const MathVector* global_corners() const + {return &vGloPos[0];} - /// number of integration points - inline size_t num_ip() const {return nip;} + /// node id that this scv is associated to + inline size_t node_id() const {return nodeId;} - /// local integration point of scv - inline const MathVector& local_ip() const {return vLocPos[0];} + /// number of integration points + inline size_t num_ip() const {return nip;} - /// global integration point - inline const MathVector& global_ip() const {return vGloPos[0];} + /// local integration point of scv + inline const MathVector& local_ip() const {return vLocPos[0];} - /// Transposed Inverse of Jacobian in integration point - inline const MathMatrix& JTInv() const {return JtInv;} + /// global integration point + inline const MathVector& global_ip() const {return vGloPos[0];} - /// Determinant of Jacobian in integration point - inline number detJ() const {return detj;} + /// Transposed Inverse of Jacobian in integration point + inline const MathMatrix& JTInv() const {return JtInv;} - /// number of shape functions - inline size_t num_sh() const {return nsh;} + /// Determinant of Jacobian in integration point + inline number detJ() const {return detj;} - /// value of shape function i in integration point - inline number shape(size_t sh) const {return vShape[sh];} + /// number of shape functions + inline size_t num_sh() const {return nsh;} - /// vector of shape functions in ip point - inline const number* shape_vector() const {return vShape;} + /// value of shape function i in integration point + inline number shape(size_t sh) const {return vShape[sh];} - /// value of local gradient of shape function i in integration point - inline const MathVector& local_grad(size_t sh) const - {UG_ASSERT(sh < num_sh(), "Invalid index"); return vLocalGrad[sh];} + /// vector of shape functions in ip point + inline const number* shape_vector() const {return vShape;} - /// vector of local gradients in ip point - inline const MathVector* local_grad_vector() const {return vLocalGrad;} + /// value of local gradient of shape function i in integration point + inline const MathVector& local_grad(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vLocalGrad[sh];} - /// value of global gradient of shape function i in integration point - inline const MathVector& global_grad(size_t sh) const - {UG_ASSERT(sh < num_sh(), "Invalid index"); return vGlobalGrad[sh];} + /// vector of local gradients in ip point + inline const MathVector* local_grad_vector() const {return vLocalGrad;} - /// vector of global gradients in ip point - inline const MathVector* global_grad_vector() const {return vGlobalGrad;} + /// value of global gradient of shape function i in integration point + inline const MathVector& global_grad(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vGlobalGrad[sh];} - private: - // let outer class access private members - friend class FV1IBGeometry; + /// vector of global gradients in ip point + inline const MathVector* global_grad_vector() const {return vGlobalGrad;} - // node id of associated node - size_t nodeId; + private: + // let outer class access private members + friend class FV1FTGeometry; - // volume of scv - number Vol; + // node id of associated node + size_t nodeId; - // local and global positions of this element - MathVector vLocPos[numCo]; // local position of node - MathVector vGloPos[numCo]; // global position of node - MidID midId[numCo]; // dimension and id of object, that's midpoint bounds the scv + // volume of scv + number Vol; - // shapes and derivatives - number vShape[nsh]; // shapes at ip - MathVector vLocalGrad[nsh]; // local grad at ip - MathVector vGlobalGrad[nsh]; // global grad at ip - MathMatrix JtInv; // Jacobian transposed at ip - number detj; // Jacobian det at ip - }; + // local and global positions of this element + MathVector vLocPos[numCo]; // local position of node + MathVector vGloPos[numCo]; // global position of node + MidID midId[numCo]; // dimension and id of object, that's midpoint bounds the scv -/// boundary face - class BF - { - public: - /// Number of corners of bf - static const size_t numCo = traits::NumCornersOfSCVF; + // shapes and derivatives + number vShape[nsh]; // shapes at ip + MathVector vLocalGrad[nsh]; // local grad at ip + MathVector vGlobalGrad[nsh]; // global grad at ip + MathMatrix JtInv; // Jacobian transposed at ip + number detj; // Jacobian det at ip + }; - public: - BF() {} + /// boundary face + class BF + { + public: + /// Number of corners of bf + static const size_t numCo = traits::NumCornersOfBF; - /// index of SubControlVolume of the bf - inline size_t node_id() const {return nodeId;} + public: + BF() {} - /// number of integration points on bf - inline size_t num_ip() const {return nip;} + /// index of SubControlVolume of the bf + inline size_t node_id() const {return nodeId;} - /// local integration point of bf - inline const MathVector& local_ip() const {return localIP;} + /// number of integration points on bf + inline size_t num_ip() const {return nip;} - /// global integration point of bf - inline const MathVector& global_ip() const {return globalIP;} + /// local integration point of bf + inline const MathVector& local_ip() const {return localIP;} - /// outer normal on bf. Norm is equal to area - inline const MathVector& normal() const {return Normal;} // includes area + /// global integration point of bf + inline const MathVector& global_ip() const {return globalIP;} - /// volume of bf - inline number volume() const {return Vol;} + /// outer normal on bf. Norm is equal to area + inline const MathVector& normal() const {return Normal;} // includes area - /// Transposed Inverse of Jacobian in integration point - inline const MathMatrix& JTInv() const {return JtInv;} + /// volume of bf + inline number volume() const {return Vol;} - /// Determinant of Jacobian in integration point - inline number detJ() const {return detj;} + /// Transposed Inverse of Jacobian in integration point + inline const MathMatrix& JTInv() const {return JtInv;} - /// number of shape functions - inline size_t num_sh() const {return nsh;} + /// Determinant of Jacobian in integration point + inline number detJ() const {return detj;} - /// value of shape function i in integration point - inline number shape(size_t sh) const - {UG_ASSERT(sh < num_sh(), "Invalid index"); return vShape[sh];} + /// number of shape functions + inline size_t num_sh() const {return nsh;} - /// vector of local gradients in ip point - inline const number* shape_vector() const {return vShape;} + /// value of shape function i in integration point + inline number shape(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vShape[sh];} - /// value of local gradient of shape function i in integration point - inline const MathVector& local_grad(size_t sh) const - {UG_ASSERT(sh < num_sh(), "Invalid index"); return vLocalGrad[sh];} + /// vector of local gradients in ip point + inline const number* shape_vector() const {return vShape;} - /// vector of local gradients in ip point - inline const MathVector* local_grad_vector() const {return vLocalGrad;} + /// value of local gradient of shape function i in integration point + inline const MathVector& local_grad(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vLocalGrad[sh];} - /// value of global gradient of shape function i in integration point - inline const MathVector& global_grad(size_t sh) const - {UG_ASSERT(sh < num_sh(), "Invalid index"); return vGlobalGrad[sh];} + /// vector of local gradients in ip point + inline const MathVector* local_grad_vector() const {return vLocalGrad;} - /// vector of global gradients in ip point - inline const MathVector* global_grad_vector() const {return vGlobalGrad;} + /// value of global gradient of shape function i in integration point + inline const MathVector& global_grad(size_t sh) const + {UG_ASSERT(sh < num_sh(), "Invalid index"); return vGlobalGrad[sh];} - /// number of corners, that bound the scvf - inline size_t num_corners() const {return numCo;} + /// vector of global gradients in ip point + inline const MathVector* global_grad_vector() const {return vGlobalGrad;} - /// return local corner number i - inline const MathVector& local_corner(size_t co) const - {UG_ASSERT(co < num_corners(), "Invalid index."); return vLocPos[co];} + /// number of corners, that bound the scvf + inline size_t num_corners() const {return numCo;} - /// return global corner number i - inline const MathVector& global_corner(size_t co) const - {UG_ASSERT(co < num_corners(), "Invalid index."); return vGloPos[co];} + /// return local corner number i + inline const MathVector& local_corner(size_t co) const + {UG_ASSERT(co < num_corners(), "Invalid index."); return vLocPos[co];} - private: - /// let outer class access private members - friend class FV1IBGeometry; + /// return global corner number i + inline const MathVector& global_corner(size_t co) const + {UG_ASSERT(co < num_corners(), "Invalid index."); return vGloPos[co];} - // id of scv this bf belongs to - size_t nodeId; + private: + /// let outer class access private members + friend class FV1FTGeometry; - // ordering is: - // 1D: edgeMidPoint - // 2D: edgeMidPoint, CenterOfElement - // 3D: edgeMidPoint, Side one, CenterOfElement, Side two - MathVector vLocPos[numCo]; // local corners of bf - MathVector vGloPos[numCo]; // global corners of bf - MidID vMidID[numCo]; // dimension and id of object, that's midpoint bounds the bf + // id of scv this bf belongs to + size_t nodeId; - // scvf part - MathVector localIP; // local integration point - MathVector globalIP; // global integration point - MathVector Normal; // normal (incl. area) - number Vol; // volume of bf + // ordering is: + // 1D: edgeMidPoint + // 2D: edgeMidPoint, CenterOfElement + // 3D: edgeMidPoint, Side one, CenterOfElement, Side two + MathVector vLocPos[numCo]; // local corners of bf + MathVector vGloPos[numCo]; // global corners of bf + MidID vMidID[numCo]; // dimension and id of object, that's midpoint bounds the bf - // shapes and derivatives - number vShape[nsh]; // shapes at ip - MathVector vLocalGrad[nsh]; // local grad at ip - MathVector vGlobalGrad[nsh]; // global grad at ip - MathMatrix JtInv; // Jacobian transposed at ip - number detj; // Jacobian det at ip - }; + // scvf part + MathVector localIP; // local integration point + MathVector globalIP; // global integration point + MathVector Normal; // normal (incl. area) + number Vol; // volume of bf + // shapes and derivatives + number vShape[nsh]; // shapes at ip + MathVector vLocalGrad[nsh]; // local grad at ip + MathVector vGlobalGrad[nsh]; // global grad at ip + MathMatrix JtInv; // Jacobian transposed at ip + number detj; // Jacobian det at ip + }; public: /// construct object and initialize local values and sizes - FV1IBGeometry(); - - /// adapt integration points for elements cut by the inner boundary - void adapt(GridObject* elem, const MathVector* vCornerCoords, - const ISubsetHandler* ish = NULL); - - /// adapt normals for elements cut by the inner boundary - void adapt_normals(GridObject* elem, const MathVector* vCornerCoords, - const ISubsetHandler* ish = NULL); - - /// adapt integration points for elements cut by the inner boundary - void adapt_integration_points(GridObject* elem, const MathVector* vCornerCoords, - const ISubsetHandler* ish = NULL); + FV1FTGeometry(); /// update local data void update_local_data(); /// update data for given element void update(GridObject* elem, const MathVector* vCornerCoords, - const ISubsetHandler* ish = NULL); + const ISubsetHandler* ish = NULL); /// update boundary data for given element void update_boundary_faces(GridObject* elem, - const MathVector* vCornerCoords, - const ISubsetHandler* ish = NULL); + const MathVector* vCornerCoords, + const ISubsetHandler* ish = NULL); + /// get the element + TElem* elem() const {return m_pElem;} + /// get vector of the global coordinates of corners for current element const MathVector* corners() const {return m_vvGloMid[0];} /// number of SubControlVolumeFaces - inline size_t num_scvf() const {return numSCVF;}; + size_t num_scvf() const {return numSCVF;}; /// const access to SubControlVolumeFace number i - inline const SCVF& scvf(size_t i) const + const SCVF& scvf(size_t i) const {UG_ASSERT(i < num_scvf(), "Invalid Index."); return m_vSCVF[i];} /// number of SubControlVolumes // do not use this method to obtain the number of shape functions, // since this is NOT the same for pyramids; use num_sh() instead. - inline size_t num_scv() const {return numSCV;} + size_t num_scv() const {return numSCV;} /// const access to SubControlVolume number i - inline const SCV& scv(size_t i) const + const SCV& scv(size_t i) const {UG_ASSERT(i < num_scv(), "Invalid Index."); return m_vSCV[i];} /// number of shape functions - inline size_t num_sh() const {return nsh;}; + size_t num_sh() const {return nsh;}; + + /// returns reference object id + ReferenceObjectID roid() const {return ref_elem_type::REFERENCE_OBJECT_ID;} + public: /// returns number of all scvf ips @@ -482,17 +481,50 @@ class FV1IBGeometry : public FVGeometryBase size_t num_scv_ips() const {return numSCV;} /// returns all ips of scv as they appear in scv loop - const MathVector* scv_local_ips() const {return &(m_vvLocMid[0][0]);} + const MathVector* scv_local_ips() const { + if(ref_elem_type::REFERENCE_OBJECT_ID == ROID_PYRAMID || ref_elem_type::REFERENCE_OBJECT_ID == ROID_OCTAHEDRON) + return &(m_vLocSCV_IP[0]); + else + return &(m_vvLocMid[0][0]); + } /// returns all ips of scv as they appear in scv loop - const MathVector* scv_global_ips() const {return &(m_vvGloMid[0][0]);} + const MathVector* scv_global_ips() const { + if(ref_elem_type::REFERENCE_OBJECT_ID == ROID_PYRAMID || ref_elem_type::REFERENCE_OBJECT_ID == ROID_OCTAHEDRON) + return &(m_vGlobSCV_IP[0]); + else + return &(m_vvGloMid[0][0]); + } + /// return local coords for node ID + const MathVector& local_node_position(size_t nodeID) const + { + UG_ASSERT(nodeID < (size_t) ref_elem_type::numCorners, "Invalid node id."); + return m_vvLocMid[0][nodeID]; + } + + /// return global coords for node ID + const MathVector& global_node_position(size_t nodeID) const + { + UG_ASSERT(nodeID < (size_t) ref_elem_type::numCorners, "Invalid node id."); + return m_vvGloMid[0][nodeID]; + } + + /// returns the local coordinates of the center of mass of the element + const MathVector* coe_local() const {return &(m_vvLocMid[dim][0]);} + + /// returns the global coordinates of the center of mass of the element + const MathVector* coe_global() const {return &(m_vvGloMid[dim][0]);} protected: // global and local ips on SCVF MathVector m_vGlobSCVF_IP[numSCVF]; MathVector m_vLocSCVF_IP[numSCVF]; + // global and local ips on SCV (only needed for Pyramid and Octahedron) + MathVector m_vGlobSCV_IP[numSCV]; + MathVector m_vLocSCV_IP[numSCV]; + public: /// add subset that is interpreted as boundary subset. inline void add_boundary_subset(int subsetIndex) {m_mapVectorBF[subsetIndex];} @@ -544,11 +576,13 @@ class FV1IBGeometry : public FVGeometryBase return (*it).second; } + void reset_curr_elem() {m_pElem = NULL;} + protected: std::map > m_mapVectorBF; std::vector m_vEmptyVectorBF; - protected: + private: /// pointer to current element TElem* m_pElem; @@ -574,13 +608,6 @@ class FV1IBGeometry : public FVGeometryBase /// Shape function set const local_shape_fct_set_type& m_rTrialSpace; - - public: - /// new members for adaptions - MathVector vSCVF_PosOnEdge[numSCVF]; // global position of scvf on edges - MathVector m_MidPoint; // global position of the midpoint, connecting each entry of PosOnEdges to a scvf - - }; //////////////////////////////////////////////////////////////////////////////// @@ -592,9 +619,8 @@ class FV1IBGeometry : public FVGeometryBase * \tparam TDim reference element dim * \tparam TWorldDim (physical) world dimension */ - -template -class DimFV1IBGeometry : public FVGeometryBase +template > +class DimFV1FTGeometry : public FVGeometryBase { public: /// used traits @@ -712,8 +738,8 @@ class DimFV1IBGeometry : public FVGeometryBase private: // let outer class access private members - friend class DimFV1IBGeometry; - + friend class DimFV1FTGeometry; + // This scvf separates the scv with the ids given in "from" and "to" // The computed normal points in direction from->to size_t From, To; @@ -754,7 +780,20 @@ class DimFV1IBGeometry : public FVGeometryBase /// volume of scv inline number volume() const {return Vol;} - + + inline number get_volume(size_t ip) const + { + if ( volIP[0] == 0.0 && volIP[1] != 0.0 ) + UG_THROW("1: error in volIP!\n"); + if ( volIP[0] != 0.0 && volIP[1] == 0.0 ) + UG_THROW("2: error in volIP!\n"); + + if ( volIP[0] == 0.0 && volIP[1] == 0.0 ) + return Vol; + + return volIP[ip]; + } + /// number of corners, that bound the scv inline size_t num_corners() const {return numCo;} @@ -809,13 +848,14 @@ class DimFV1IBGeometry : public FVGeometryBase private: // let outer class access private members - friend class DimFV1IBGeometry; - + friend class DimFV1FTGeometry; + // node id of associated node size_t nodeId; // volume of scv number Vol; + number volIP[2]; // local and global positions of this element MathVector vLocPos[numCo]; // local position of node @@ -902,7 +942,7 @@ class DimFV1IBGeometry : public FVGeometryBase private: /// let outer class access private members - friend class DimFV1IBGeometry; + friend class DimFV1FTGeometry; // id of scv this bf belongs to size_t nodeId; @@ -932,23 +972,44 @@ class DimFV1IBGeometry : public FVGeometryBase public: /// construct object and initialize local values and sizes - DimFV1IBGeometry() : m_pElem(NULL), m_roid(ROID_UNKNOWN) {}; - - /// adapt integration points for elements cut by the inner boundary - void adapt(GridObject* elem, const MathVector* vCornerCoords, - const ISubsetHandler* ish = NULL); - - /// adapt normals for elements cut by the inner boundary - void adapt_normals(GridObject* elem, const MathVector* vCornerCoords, - const ISubsetHandler* ish = NULL); - - /// adapt integration points for elements cut by the inner boundary - void adapt_integration_points(GridObject* elem, const MathVector* vCornerCoords, - const ISubsetHandler* ish = NULL); - - /// update local data - void update_local_data(); - + DimFV1FTGeometry() : m_pElem(NULL), m_roid(ROID_UNKNOWN) {}; + + ////////////////////////////////////////////////////////////////////////////// + /// new FT-methods + ////////////////////////////////////////////////////////////////////////////// + + inline const size_t get_original_node(size_t i) const {return m_spInterfaceHandler->corner_orig(i);} + inline const size_t get_interface_id(size_t i) + { + std::vector interfaceIDs = m_spInterfaceHandler->interface_id_all(); + return get_original_node(interfaceIDs[i]); + } + bool lies_onInterface(const size_t newID) + { return m_spInterfaceHandler->lies_onInterface(newID); } + + + inline void set_element_modus(bool boolian) { mElemModus = boolian;} + inline const bool get_element_modus() { return mElemModus;} + inline const ReferenceObjectID get_roid() const {return m_roid;} + inline ElementModus return_element_modus() { return m_spInterfaceHandler->elementModus(); } + + /// called during 'ParticleBndCond::add_def_M_local()': + const number volume_fem_elem() const {UG_THROW("FV1FTGeom::volume_fem_elem() not implemented!\n");} + const number volume_FT_elem() const {UG_THROW("FV1FTGeom::volume_FT_elem() not implemented!\n");} + + number get_volume(size_t ip) const { return m_vVol_IP[ip]; } + + bool mElemModus; + + /// set the local interface handler + /// (called during constructor of class 'ImmersedInterface') + void set_interface_handler(SmartPtr localHandler) + { m_spInterfaceHandler = localHandler; } + + ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// + + /// update data for given element void update(GridObject* elem, const MathVector* vCornerCoords, const ISubsetHandler* ish = NULL); @@ -958,27 +1019,30 @@ class DimFV1IBGeometry : public FVGeometryBase const MathVector* vCornerCoords, const ISubsetHandler* ish = NULL); + /// get the element + GridObject* elem() const {return m_pElem;} + /// get vector of corners for current element const MathVector* corners() const {return m_vvGloMid[0];} /// number of SubControlVolumeFaces - inline size_t num_scvf() const {return m_numSCVF;}; + size_t num_scvf() const {return m_numSCVF;}; /// const access to SubControlVolumeFace number i - inline const SCVF& scvf(size_t i) const + const SCVF& scvf(size_t i) const {UG_ASSERT(i < num_scvf(), "Invalid Index."); return m_vSCVF[i];} /// number of SubControlVolumes // do not use this method to obtain the number of shape functions, // since this is NOT the same for pyramids; use num_sh() instead. - inline size_t num_scv() const {return m_numSCV;} + size_t num_scv() const {return m_numSCV;} /// const access to SubControlVolume number i - inline const SCV& scv(size_t i) const + const SCV& scv(size_t i) const {UG_ASSERT(i < num_scv(), "Invalid Index."); return m_vSCV[i];} /// number of shape functions - inline size_t num_sh() const {return m_nsh;}; + size_t num_sh() const {return m_nsh;}; public: /// returns number of all scvf ips @@ -994,17 +1058,77 @@ class DimFV1IBGeometry : public FVGeometryBase size_t num_scv_ips() const {return m_numSCV;} /// returns all ips of scv as they appear in scv loop - const MathVector* scv_local_ips() const {return &(m_vvLocMid[0][0]);} + const MathVector* scv_local_ips() const { + if(m_roid == ROID_PYRAMID || m_roid == ROID_OCTAHEDRON) + return &(m_vLocSCV_IP[0]); + else + return &(m_vvLocMid[0][0]); + } /// returns all ips of scv as they appear in scv loop - const MathVector* scv_global_ips() const {return &(m_vvGloMid[0][0]);} + const MathVector* scv_global_ips() const { + if(m_roid == ROID_PYRAMID || m_roid == ROID_OCTAHEDRON) + return &(m_vGlobSCV_IP[0]); + else + return &(m_vvGloMid[0][0]); + } + /// returns the local coordinates of the center of mass of the element + const MathVector* coe_local() const {return &(m_vvLocMid[dim][0]);} + + /// returns the global coordinates of the center of mass of the element + const MathVector* coe_global() const {return &(m_vvGloMid[dim][0]);} + /// returns reference object id + ReferenceObjectID roid() const {return m_roid;} + + /// update local data + void update_local(ReferenceObjectID roid); + + ////////////////////////////////////////////////////////////////////////////// + /// new FT-methods + ////////////////////////////////////////////////////////////////////////////// + + /// update boundary faces on interface; call during update() + void update_inner_boundary_faces(); + void update_inner_boundary_faces_for2(); + + /// if OUTSIDE_DOM within update() + void set_local_data_to_zero(){ m_numSCVF = m_numSCV = m_nsh = 0;} + +/* ToDo + /// final computations within update() + void remap_shapes_and_derivatives(ReferenceObjectID roid); + + /// computations for remapping SCVF + void copy_SCVF(SCVF vSCVF[maxNumSCVF]); + void remap_add_SCVF(SCVF vSCVF[maxNumSCVF], size_t numSH); + + /// computations for remapping SCV + void copy_SCV(SCV vSCV[maxNumSCV]); + void remap_add_SCV(SCV vSCV[maxNumSCV], size_t numSH); + + /// computations for remapping m_spInterfaceHandler.m_vBF + void copy_BF(BF vBF[maxNumSCV] ); + void remap_BF(BF vBF[maxNumSCV], size_t numSH); + +*/ + + ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// + + protected: // global and local ips on SCVF MathVector m_vGlobSCVF_IP[maxNumSCVF]; MathVector m_vLocSCVF_IP[maxNumSCVF]; + // global and local ips on SCV (only needed for Pyramid and Octahedron) + MathVector m_vGlobSCV_IP[maxNumSCV]; + MathVector m_vLocSCV_IP[maxNumSCV]; + + number m_vVol_IP[2]; + public: /// add subset that is interpreted as boundary subset. inline void add_boundary_subset(int subsetIndex) {m_mapVectorBF[subsetIndex];} @@ -1042,7 +1166,7 @@ class DimFV1IBGeometry : public FVGeometryBase { typename std::map >::const_iterator it; it = m_mapVectorBF.find(si); - if(it == m_mapVectorBF.end()) UG_THROW("DimFV1IBGeom: No BndSubset "< vSCVF_PosOnEdge[maxNumSCVF]; // global position of scvf on edges - MathVector m_MidPoint; // global position of the midpoint, connecting each entry of PosOnEdges to a scvf - + + //////////////////////////////////////////////////////////////////////////////// + // FV1FT data + //////////////////////////////////////////////////////////////////////////////// + + // InterfaceHandlerLocalParticle: derived from class 'IInterfaceHandlerLocal' + SmartPtr m_spInterfaceHandler; + + bool m_bIsFlatTopElement; + }; +} - -#include "fv1ib_geom_impl.h" - -} // end ug namespace - -#endif /* FV1IB_GEOM_H_ */ +#endif /* __H__UG__LIB_DISC__SPATIAL_DISC__DISC_HELPER__FV1FT_GEOMETRY__ */ diff --git a/ugbase/lib_disc/spatial_disc/disc_util/fv1ib_geom_impl.h b/ugbase/lib_disc/spatial_disc/disc_util/fv1ib_geom_impl.h deleted file mode 100644 index 422f8712d..000000000 --- a/ugbase/lib_disc/spatial_disc/disc_util/fv1ib_geom_impl.h +++ /dev/null @@ -1,1324 +0,0 @@ -/* - * Copyright (c) 2014-2015: G-CSC, Goethe University Frankfurt - * Author: Susanne Höllbacher - * - * This file is part of UG4. - * - * UG4 is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License version 3 (as published by the - * Free Software Foundation) with the following additional attribution - * requirements (according to LGPL/GPL v3 §7): - * - * (1) The following notice must be displayed in the Appropriate Legal Notices - * of covered and combined works: "Based on UG4 (www.ug4.org/license)". - * - * (2) The following notice must be displayed at a prominent place in the - * terminal output of covered works: "Based on UG4 (www.ug4.org/license)". - * - * (3) The following bibliography is recommended for citation and must be - * preserved in all covered files: - * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively - * parallel geometric multigrid solver on hierarchically distributed grids. - * Computing and visualization in science 16, 4 (2013), 151-164" - * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel - * flexible software system for simulating pde based models on high performance - * computers. Computing and visualization in science 16, 4 (2013), 165-179" - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License for more details. - */ - -/* - * copy of 'fv1_geom.h' with two additional methods: - * 'adapt_normals()' and 'adapt_integration_points()' - */ - - -#include "common/util/provider.h" - #include "fv1ib_geom.h" -#include "lib_disc/reference_element/reference_element.h" -#include "lib_disc/quadrature/quadrature.h" -#include "lib_algebra/common/operations_vec.h" - -template -void FV1IBGeometry:: - adapt(GridObject* elem, const MathVector* vCornerCoords, - const ISubsetHandler* ish) -{ - - for(size_t ip = 0; ip < num_scvf(); ++ip) - UG_LOG("#### vSCVF_PosOnEdge = " << vSCVF_PosOnEdge[ip] << "\n"); - -// compute global informations for scvf - for(size_t i = 0; i < num_scvf(); ++i) - { - UG_LOG("ip's: " << m_vSCVF[i].globalIP << "\n"); - UG_LOG("normals: " << m_vSCVF[i].Normal << "\n"); - - } - -// compute global informations for scvf - for(size_t i = 0; i < num_scvf(); ++i) - { - //VecScaleAdd(m_vSCVF[i].globalIP, vSCVF_PosOnEdge[i], 0.5, m_MidPoint, 0.5); - for(size_t d = 0; d < m_vSCVF[i].globalIP.size(); ++d) - m_vSCVF[i].globalIP[d] = 0.5*(vSCVF_PosOnEdge[i][d] + m_MidPoint[d]); - - //traits::NormalOnSCVF(m_vSCVF[i].Normal, vSCVF_PosOnEdge[i], m_MidPoint); - // 'NormalOnSCVF' braucht Felder im 2. und 3. Parameter - //traits::NormalOnSCVF(m_vSCVF[i].Normal, vSCVF_PosOnEdge, vSCVF_PosOnEdge); - MathVector buffer_comp; - VecSubtract(buffer_comp, vSCVF_PosOnEdge[i], m_MidPoint); - - MathVector buffer_copy; - buffer_copy[0] = -buffer_comp[1]; - buffer_copy[1] = buffer_comp[0]; - - // check the orientation of the newly computet Normal: - // -> has to be in direction from -> to, i.e. VecDot(Normal_alt, Normal_neu) > 0 - if ( VecDot(m_vSCVF[i].Normal, buffer_copy) > 0 ) - { - UG_LOG("Positiv: normals: " << m_vSCVF[i].Normal << "\n"); - UG_LOG("Positiv: normals: " << buffer_copy << "\n"); - - m_vSCVF[i].Normal[0] = buffer_copy[0]; - m_vSCVF[i].Normal[1] = buffer_copy[1]; - } - else - { - UG_LOG("Negativ: normals: " << m_vSCVF[i].Normal << "\n"); - UG_LOG("Negativ: normals: " << buffer_copy << "\n"); - - m_vSCVF[i].Normal[0] = -buffer_copy[0]; - m_vSCVF[i].Normal[1] = -buffer_copy[1]; - } - - - UG_LOG("***ip's: " << m_vSCVF[i].globalIP << "\n"); - UG_LOG("***normals: " << m_vSCVF[i].Normal << "\n"); - UG_LOG("***buffer_copy: " << buffer_copy << "\n"); - - } - - //UG_THROW("### ok done...\n"); -} - - -template -void FV1IBGeometry:: -adapt_integration_points(GridObject* elem, const MathVector* vCornerCoords, - const ISubsetHandler* ish) -{ - UG_THROW("adapt_integration_points: ok done...\n"); - -} - -template -void FV1IBGeometry:: -adapt_normals(GridObject* elem, const MathVector* vCornerCoords, - const ISubsetHandler* ish) -{ -/// BEACHTE: -/// normal on scvf (points direction "from"->"to") - - - for(size_t i = 0; i < num_scvf(); ++i) - { - UG_LOG("ip's: " << m_vSCVF[i].globalIP << "\n"); - UG_LOG("normals: " << m_vSCVF[i].Normal << "\n"); - - } - - UG_THROW("stop hier...\n"); - - -} - - - -/** - * \tparam dim dimension of coordinates - * \tparam TRefElem Reference element type - * \tparam maxMid Maximum number of elements for all dimensions - */ -template -static void ComputeMidPoints(const TRefElem& rRefElem, - const MathVector vCorner[], - MathVector vvMid[][maxMid]) -{ -// compute local midpoints for all geometric objects with 0 < d <= dim - for(int d = 1; d <= dim; ++d) - { - // loop geometric objects of dimension d - for(size_t i = 0; i < rRefElem.num(d); ++i) - { - // set first node - const size_t coID0 = rRefElem.id(d, i, 0, 0); - vvMid[d][i] = vCorner[coID0]; - - // add corner coordinates of the corners of the geometric object - for(size_t j = 1; j < rRefElem.num(d, i, 0); ++j) - { - const size_t coID = rRefElem.id(d, i, 0, j); - vvMid[d][i] += vCorner[coID]; - } - - // scale for correct averaging - vvMid[d][i] *= 1./(rRefElem.num(d, i, 0)); - } - } - - // for PYRAMIDS: add midpoints of imaginary faces, edges and volumes - // resulting from the division into two tetrahedra alongside x==y - if (rRefElem.roid() == ROID_PYRAMID) - { - // diagonal 2->0, diagonal 0->2 - VecScaleAdd(vvMid[1][rRefElem.num(1)], 0.5, vCorner[2], 0.5, vCorner[0]); - VecScaleAdd(vvMid[1][rRefElem.num(1)+1], 0.5, vCorner[0], 0.5, vCorner[2]); - - // subface 0,1,2; subface 0,2,3; face 0,4,2; face 0,2,4 - vvMid[2][rRefElem.num(2)] = vCorner[0]; - vvMid[2][rRefElem.num(2)] += vCorner[1]; - vvMid[2][rRefElem.num(2)] += vCorner[2]; - vvMid[2][rRefElem.num(2)] *= 1.0/3.0; - - vvMid[2][rRefElem.num(2)+1] = vCorner[0]; - vvMid[2][rRefElem.num(2)+1] += vCorner[2]; - vvMid[2][rRefElem.num(2)+1] += vCorner[3]; - vvMid[2][rRefElem.num(2)+1] *= 1.0/3.0; - - vvMid[2][rRefElem.num(2)+2] = vCorner[0]; - vvMid[2][rRefElem.num(2)+2] += vCorner[4]; - vvMid[2][rRefElem.num(2)+2] += vCorner[2]; - vvMid[2][rRefElem.num(2)+2] *= 1.0/3.0; - - vvMid[2][rRefElem.num(2)+3] = vCorner[0]; - vvMid[2][rRefElem.num(2)+3] += vCorner[2]; - vvMid[2][rRefElem.num(2)+3] += vCorner[4]; - vvMid[2][rRefElem.num(2)+3] *= 1.0/3.0; - - // subvolume 0,1,2,4; subvolume 0,2,3,4 - - vvMid[3][rRefElem.num(3)] = vCorner[0]; - vvMid[3][rRefElem.num(3)] += vCorner[1]; - vvMid[3][rRefElem.num(3)] += vCorner[2]; - vvMid[3][rRefElem.num(3)] += vCorner[4]; - vvMid[3][rRefElem.num(3)] *= 0.25; - - vvMid[3][rRefElem.num(3)+1] = vCorner[0]; - vvMid[3][rRefElem.num(3)+1] += vCorner[2]; - vvMid[3][rRefElem.num(3)+1] += vCorner[3]; - vvMid[3][rRefElem.num(3)+1] += vCorner[4]; - vvMid[3][rRefElem.num(3)+1] *= 0.25; - } -} - -/** - * \param[in] i indicates that scvf corresponds to i'th edge of ref elem - */ -template -static void ComputeSCVFMidID(const TRefElem& rRefElem, - MidID vMidID[], int i) -{ - static const int dim = TRefElem::dim; - - if (rRefElem.roid() != ROID_PYRAMID) - { - // set mid ids - { - // start at edge midpoint - vMidID[0] = MidID(1,i); - - // loop up dimension - if(dim == 2) - { - vMidID[1] = MidID(dim, 0); // center of element - } - else if (dim == 3) - { - vMidID[1] = MidID(2, rRefElem.id(1, i, 2, 0)); // side 0 - vMidID[2] = MidID(dim, 0); // center of element - vMidID[3] = MidID(2, rRefElem.id(1, i, 2, 1)); // side 1 - } - } - } - // pyramid here - else - { - switch (i) - { - // scvf of edge 0 - case 0: vMidID[0] = MidID(1,0); // edge 0 - vMidID[1] = MidID(2,5); // subface 0/0 - vMidID[2] = MidID(3,1); // subvolume 0/0 - vMidID[3] = MidID(2,1); // face 1 - break; - // scvf of edge 1 - case 1: vMidID[0] = MidID(1,1); // edge 1 - vMidID[1] = MidID(2,5); // subface 0/0 - vMidID[2] = MidID(3,1); // subvolume 0/0 - vMidID[3] = MidID(2,2); // face 2 - break; - // scvf of diagonal 2->0 - case 2: vMidID[0] = MidID(1,8); // diagonal 2->0 - vMidID[1] = MidID(2,5); // subface 0/0 - vMidID[2] = MidID(3,1); // subvolume 0/0 - vMidID[3] = MidID(2,7); // face 0,4,2 - break; - // scvf of edge 4 in subvolume 0/0 - case 3: vMidID[0] = MidID(1,4); // edge 4 - vMidID[1] = MidID(2,1); // face 1 - vMidID[2] = MidID(3,1); // subvolume 0/0 - vMidID[3] = MidID(2,7); // face 0,4,2 - break; - // scvf of edge 5 - case 4: vMidID[0] = MidID(1,5); // edge 5 - vMidID[1] = MidID(2,2); // face 2 - vMidID[2] = MidID(3,1); // subvolume 0/0 - vMidID[3] = MidID(2,1); // face 1 - break; - // scvf of edge 6 in subvolume 0/0 - case 5: vMidID[0] = MidID(1,6); // edge 6 - vMidID[1] = MidID(2,7); // face 0,4,2 - vMidID[2] = MidID(3,1); // subvolume 0/0 - vMidID[3] = MidID(2,2); // face 2 - break; - // edge 0->2 - case 6: vMidID[0] = MidID(1,9); // edge 0->2 - vMidID[1] = MidID(2,6); // subface 1/0 - vMidID[2] = MidID(3,2); // subvolume 1/0 - vMidID[3] = MidID(2,8); // face 0,2,4 - break; - // scvf of edge 2 - case 7: vMidID[0] = MidID(1,2); // edge 2 - vMidID[1] = MidID(2,6); // subface 1/0 - vMidID[2] = MidID(3,2); // subvolume 1/0 - vMidID[3] = MidID(2,3); // face 3 - break; - // scvf of edge 3 - case 8: vMidID[0] = MidID(1,3); // edge 3 - vMidID[1] = MidID(2,6); // subface 1/0 - vMidID[2] = MidID(3,2); // subvolume 1/0 - vMidID[3] = MidID(2,4); // face 4 - break; - // scvf of edge 4 in subvolume 1/0 - case 9: vMidID[0] = MidID(1,4); // edge 4 - vMidID[1] = MidID(2,8); // face 0,2,4 - vMidID[2] = MidID(3,2); // subvolume 1/0 - vMidID[3] = MidID(2,4); // face 4 - break; - // scvf of edge 6 in subvolume 1/0 - case 10:vMidID[0] = MidID(1,6); // edge 6 - vMidID[1] = MidID(2,3); // face 3 - vMidID[2] = MidID(3,2); // subvolume 1/0 - vMidID[1] = MidID(2,8); // face 0,2,4 - break; - // scvf of edge 7 - case 11:vMidID[0] = MidID(1,7); // edge 7 - vMidID[3] = MidID(2,4); // face 4 - vMidID[2] = MidID(3,2); // subvolume 1/0 - vMidID[1] = MidID(2,3); // face 3 - break; - default:UG_THROW("Pyramid only has 12 SCVFs (no. 0-11), but requested no. " << i << "."); - break; - } - } -} - -/** - * \param[in] i indicates that scvf corresponds to i'th corner of ref elem - */ -template -static void ComputeSCVMidID(const TRefElem& rRefElem, - MidID vMidID[], int i) -{ - static const int dim = TRefElem::dim; - - if (rRefElem.roid() != ROID_PYRAMID) - { - if(dim == 1) - { - vMidID[0] = MidID(0, i); // set node as corner of scv - vMidID[1] = MidID(dim, 0); // center of element - } - else if(dim == 2) - { - vMidID[0] = MidID(0, i); // set node as corner of scv - vMidID[1] = MidID(1, rRefElem.id(0, i, 1, 0)); // edge 1 - vMidID[2] = MidID(dim, 0); // center of element - vMidID[3] = MidID(1, rRefElem.id(0, i, 1, 1)); // edge 2 - } - else if(dim == 3) - { - vMidID[0] = MidID(0, i); // set node as corner of scv - vMidID[1] = MidID(1, rRefElem.id(0, i, 1, 1)); // edge 1 - vMidID[2] = MidID(2, rRefElem.id(0, i, 2, 0)); // face 0 - vMidID[3] = MidID(1, rRefElem.id(0, i, 1, 0)); // edge 0 - vMidID[4] = MidID(1, rRefElem.id(0, i, 1, 2)); // edge 2 - vMidID[5] = MidID(2, rRefElem.id(0, i, 2, 2)); // face 2 - vMidID[6] = MidID(dim, 0); // center of element - vMidID[7] = MidID(2, rRefElem.id(0, i, 2, 1)); // face 1 - } - else {UG_THROW("Dimension higher that 3 not implemented.");} - } - // pyramid here - else - { - switch (i) - { - // scv of corner 0 in subvolume 0/0 - case 0: vMidID[0] = MidID(0,0); // corner 0 - vMidID[1] = MidID(1,0); // edge 0 - vMidID[2] = MidID(2,5); // subface 0/0 - vMidID[3] = MidID(1,8); // edge 2->0 - vMidID[4] = MidID(1,4); // edge 4 - vMidID[5] = MidID(2,1); // face 1 - vMidID[6] = MidID(3,1); // subvolume 0/0 - vMidID[7] = MidID(2,7); // face 0,4,2 - break; - // scv of corner 1 - case 1: vMidID[0] = MidID(0,1); // corner 1 - vMidID[1] = MidID(1,1); // edge 1 - vMidID[2] = MidID(2,5); // subface 0/0 - vMidID[3] = MidID(1,0); // edge 0 - vMidID[4] = MidID(1,5); // edge 5 - vMidID[5] = MidID(2,2); // face 2 - vMidID[6] = MidID(3,1); // subvolume 0/0 - vMidID[7] = MidID(2,1); // face 1 - break; - // scv of corner 2 in subvolume 0/0 - case 2: vMidID[0] = MidID(0,2); // corner 2 - vMidID[1] = MidID(1,8); // edge 2->0 - vMidID[2] = MidID(2,5); // subface 0/0 - vMidID[3] = MidID(1,1); // edge 1 - vMidID[4] = MidID(1,6); // edge 6 - vMidID[5] = MidID(2,7); // face 0,4,2 - vMidID[6] = MidID(3,1); // subvolume 0/0 - vMidID[7] = MidID(2,2); // face 2 - break; - // scv of corner 4 in subvolume 0/0 - case 3: vMidID[0] = MidID(0,4); // corner 4 - vMidID[1] = MidID(1,5); // edge 5 - vMidID[2] = MidID(2,1); // face 1 - vMidID[3] = MidID(1,4); // edge 4 - vMidID[4] = MidID(1,6); // edge 6 - vMidID[5] = MidID(2,2); // face 2 - vMidID[6] = MidID(3,1); // subvolume 0/0 - vMidID[7] = MidID(2,7); // face 0,4,2 - break; - // scv of corner 0 in subvolume 1/0 - case 4: vMidID[0] = MidID(0,0); // corner 0 - vMidID[1] = MidID(1,9); // edge 0->2 - vMidID[2] = MidID(2,6); // subface 1/0 - vMidID[3] = MidID(1,3); // edge 3 - vMidID[4] = MidID(1,4); // edge 4 - vMidID[5] = MidID(2,8); // face 0,2,4 - vMidID[6] = MidID(3,2); // subvolume 1/0 - vMidID[7] = MidID(2,4); // face 4 - break; - // scv of corner 2 in subvolume 1/0 - case 5: vMidID[0] = MidID(0,2); // corner 2 - vMidID[1] = MidID(1,2); // edge 2 - vMidID[2] = MidID(2,6); // subface 1/0 - vMidID[3] = MidID(1,9); // edge 0->2 - vMidID[4] = MidID(1,6); // edge 6 - vMidID[5] = MidID(2,3); // face 3 - vMidID[6] = MidID(3,2); // subvolume 1/0 - vMidID[7] = MidID(2,8); // face 0,2,4 - break; - // scv of corner 3 - case 6: vMidID[0] = MidID(0,3); // corner 3 - vMidID[1] = MidID(1,3); // edge 3 - vMidID[2] = MidID(2,6); // subface 1/0 - vMidID[3] = MidID(1,2); // edge 2 - vMidID[4] = MidID(1,7); // edge 7 - vMidID[5] = MidID(2,4); // face 4 - vMidID[6] = MidID(3,2); // subvolume 1/0 - vMidID[7] = MidID(2,3); // face 3 - break; - // scv of corner 4 in subvolume 1/0 - case 7: vMidID[0] = MidID(0,4); // corner 4 - vMidID[1] = MidID(1,6); // edge 6 - vMidID[2] = MidID(2,8); // face 0,2,4 - vMidID[3] = MidID(1,4); // edge 4 - vMidID[4] = MidID(1,7); // edge 7 - vMidID[5] = MidID(2,3); // face 3 - vMidID[6] = MidID(3,2); // subvolume 1/0 - vMidID[7] = MidID(2,4); // face 4 - break; - default:UG_THROW("Pyramid only has 8 SCVs (no. 0-7), but requested no. " << i << "."); - break; - } - } -} - -/** - * \param[in] i indicates that scvf corresponds to i'th corner of ref elem - */ -template -static void ComputeBFMidID(const TRefElem& rRefElem, int side, - MidID vMidID[], int co) -{ - static const int dim = TRefElem::dim; - - if (rRefElem.roid() != ROID_PYRAMID || side != 0) - { - // number of corners of side - const int coOfSide = rRefElem.num(dim-1, side, 0); - - // set mid ids - if(dim == 2) - { - vMidID[co%2] = MidID(0, rRefElem.id(1, side, 0, co)); // corner of side - vMidID[(co+1)%2] = MidID(1, side); // side midpoint - } - else if (dim == 3) - { - vMidID[0] = MidID(0, rRefElem.id(2, side, 0, co)); // corner of side - vMidID[1] = MidID(1, rRefElem.id(2, side, 1, co)); // edge co - vMidID[2] = MidID(2, side); // side midpoint - vMidID[3] = MidID(1, rRefElem.id(2, side, 1, (co -1 + coOfSide)%coOfSide)); // edge co-1 - } - } - // bottom side of pyramid here - else - { - switch (co) - { - // bf of corner 0 in subface 0/0 - case 0: vMidID[0] = MidID(0,0); // corner 0 - vMidID[1] = MidID(1,8); // edge 2->0 - vMidID[2] = MidID(2,5); // subface 0/0 - vMidID[3] = MidID(1,0); // edge 0 - break; - // bf of corner 1 - case 1: vMidID[0] = MidID(0,1); // corner 1 - vMidID[1] = MidID(1,0); // edge 0 - vMidID[2] = MidID(2,5); // subface 0/0 - vMidID[3] = MidID(1,1); // edge 1 - break; - // bf of corner 2 in subvolume 0/0 - case 2: vMidID[0] = MidID(0,2); // corner 2 - vMidID[1] = MidID(1,1); // edge 1 - vMidID[2] = MidID(2,5); // subface 0/0 - vMidID[3] = MidID(1,8); // edge 2->0 - break; - // bf of corner 0 in subvolume 1/0 - case 3: vMidID[0] = MidID(0,0); // corner 0 - vMidID[1] = MidID(1,3); // edge 3 - vMidID[2] = MidID(2,6); // subface 1/0 - vMidID[3] = MidID(1,9); // edge 0->2 - break; - // bf of corner 2 in subvolume 1/0 - case 4: vMidID[0] = MidID(0,2); // corner 2 - vMidID[1] = MidID(1,9); // edge 0->2 - vMidID[2] = MidID(2,6); // subface 1/0 - vMidID[3] = MidID(1,2); // edge 2 - break; - // bf of corner 3 - case 5: vMidID[0] = MidID(0,3); // corner 3 - vMidID[1] = MidID(1,2); // edge 2 - vMidID[2] = MidID(2,6); // subface 1/0 - vMidID[3] = MidID(1,3); // edge 3 - break; - default:UG_THROW("Pyramid only has 6 BFs on bottom side (no. 0-5), but requested no. " << co << "."); - break; - } - } -} - -template -static void CopyCornerByMidID(MathVector vCorner[], - const MidID vMidID[], - MathVector vvMidPos[][maxMid], - const size_t numCo) -{ - for(size_t i = 0; i < numCo; ++i) - { - const size_t d = vMidID[i].dim; - const size_t id = vMidID[i].id; - vCorner[i] = vvMidPos[d][id]; - } -} - -//////////////////////////////////////////////////////////////////////////////// -// FV1 Geometry for Reference Element Type -//////////////////////////////////////////////////////////////////////////////// - -template -FV1IBGeometry:: -FV1IBGeometry() - : m_pElem(NULL), m_rRefElem(Provider::get()), - m_rTrialSpace(Provider::get()) -{ - update_local_data(); -} - -template -void FV1IBGeometry:: -update_local_data() -{ -// set corners of element as local centers of nodes - for(size_t i = 0; i < m_rRefElem.num(0); ++i) - m_vvLocMid[0][i] = m_rRefElem.corner(i); - -// compute local midpoints - ComputeMidPoints(m_rRefElem, m_vvLocMid[0], m_vvLocMid); - -// set up local information for SubControlVolumeFaces (scvf) - for(size_t i = 0; i < num_scvf(); ++i) - { - - // this scvf separates the given nodes - if (m_rRefElem.REFERENCE_OBJECT_ID != ROID_PYRAMID) - { - m_vSCVF[i].From = m_rRefElem.id(1, i, 0, 0); - m_vSCVF[i].To = m_rRefElem.id(1, i, 0, 1); - } - // special case pyramid (scvf not mappable by edges) - else - { - // map according to order defined in ComputeSCVFMidID - m_vSCVF[i].From = ((i>6 && i%3) ? (i%3)+1 : i%3); - m_vSCVF[i].To = i%6 > 2 ? 4 : ((i+1)%3 + (i>5 && i<8 ? 1 : 0)); - } - - // compute mid ids of the scvf - ComputeSCVFMidID(m_rRefElem, m_vSCVF[i].vMidID, i); - - // copy local corners of scvf - CopyCornerByMidID(m_vSCVF[i].vLocPos, m_vSCVF[i].vMidID, m_vvLocMid, SCVF::numCo); - - // integration point - AveragePositions(m_vSCVF[i].localIP, m_vSCVF[i].vLocPos, SCVF::numCo); - } - -// set up local informations for SubControlVolumes (scv) -// each scv is associated to one corner of the element - for(size_t i = 0; i < num_scv(); ++i) - { - // store associated node - if (m_rRefElem.REFERENCE_OBJECT_ID != ROID_PYRAMID) - { - m_vSCV[i].nodeId = i; - } - // special case pyramid (scv not mappable by corners) - else - { - // map according to order defined in ComputeSCVMidID - m_vSCV[i].nodeId = i<3 ? i : (i<5 ? (i+1)%5 : i-3); - } - - // compute mid ids scv - ComputeSCVMidID(m_rRefElem, m_vSCV[i].midId, i); - - // copy local corners of scv - CopyCornerByMidID(m_vSCV[i].vLocPos, m_vSCV[i].midId, m_vvLocMid, m_vSCV[i].num_corners()); - } - - -// compute Shapes and Derivatives - for(size_t i = 0; i < num_scvf(); ++i) - { - m_rTrialSpace.shapes(&(m_vSCVF[i].vShape[0]), m_vSCVF[i].local_ip()); - m_rTrialSpace.grads(&(m_vSCVF[i].vLocalGrad[0]), m_vSCVF[i].local_ip()); - } - - for(size_t i = 0; i < num_scv(); ++i) - { - m_rTrialSpace.shapes(&(m_vSCV[i].vShape[0]), m_vSCV[i].local_ip()); - m_rTrialSpace.grads(&(m_vSCV[i].vLocalGrad[0]), m_vSCV[i].local_ip()); - } - -// copy ip positions in a list for Sub Control Volumes Faces (SCVF) - for(size_t i = 0; i < num_scvf(); ++i) - m_vLocSCVF_IP[i] = scvf(i).local_ip(); -} - -/// update data for given element -template -void FV1IBGeometry:: -update(GridObject* elem, const MathVector* vCornerCoords, const ISubsetHandler* ish) -{ - - UG_ASSERT(dynamic_cast(elem) != NULL, "Wrong element type."); - TElem* pElem = static_cast(elem); - -// if already update for this element, do nothing - if(m_pElem == pElem) return; else m_pElem = pElem; - -// remember global position of nodes - for(size_t i = 0; i < m_rRefElem.num(0); ++i) - m_vvGloMid[0][i] = vCornerCoords[i]; - -// compute global midpoints - ComputeMidPoints(m_rRefElem, m_vvGloMid[0], m_vvGloMid); - -// compute global informations for scvf - for(size_t i = 0; i < num_scvf(); ++i) - { - // copy local corners of scvf - CopyCornerByMidID(m_vSCVF[i].vGloPos, m_vSCVF[i].vMidID, m_vvGloMid, SCVF::numCo); - - // integration point - AveragePositions(m_vSCVF[i].globalIP, m_vSCVF[i].vGloPos, SCVF::numCo); - - // normal on scvf - traits::NormalOnSCVF(m_vSCVF[i].Normal, m_vSCVF[i].vGloPos, m_vvGloMid[0]); - } - -// compute size of scv - for(size_t i = 0; i < num_scv(); ++i) - { - // copy global corners - CopyCornerByMidID(m_vSCV[i].vGloPos, m_vSCV[i].midId, m_vvGloMid, m_vSCV[i].num_corners()); - - // compute volume of scv - m_vSCV[i].Vol = ElementSize(m_vSCV[i].vGloPos); - } - -// Shapes and Derivatives - m_mapping.update(vCornerCoords); - -// if mapping is linear, compute jacobian only once and copy - if(ReferenceMapping::isLinear) - { - MathMatrix JtInv; - m_mapping.jacobian_transposed_inverse(JtInv, m_vSCVF[0].local_ip()); - const number detJ = m_mapping.sqrt_gram_det(m_vSCVF[0].local_ip()); - - for(size_t i = 0; i < num_scvf(); ++i) - { - m_vSCVF[i].JtInv = JtInv; - m_vSCVF[i].detj = detJ; - } - - for(size_t i = 0; i < num_scv(); ++i) - { - m_vSCV[i].JtInv = JtInv; - m_vSCV[i].detj = detJ; - } - } -// else compute jacobian for each integration point - else - { - for(size_t i = 0; i < num_scvf(); ++i) - { - m_mapping.jacobian_transposed_inverse(m_vSCVF[i].JtInv, m_vSCVF[i].local_ip()); - m_vSCVF[i].detj = m_mapping.sqrt_gram_det(m_vSCVF[i].local_ip()); - } - for(size_t i = 0; i < num_scv(); ++i) - { - m_mapping.jacobian_transposed_inverse(m_vSCV[i].JtInv, m_vSCV[i].local_ip()); - m_vSCV[i].detj = m_mapping.sqrt_gram_det(m_vSCV[i].local_ip()); - } - } - -// compute global gradients - for(size_t i = 0; i < num_scvf(); ++i) - for(size_t sh = 0 ; sh < scvf(i).num_sh(); ++sh) - MatVecMult(m_vSCVF[i].vGlobalGrad[sh], m_vSCVF[i].JtInv, m_vSCVF[i].vLocalGrad[sh]); - - for(size_t i = 0; i < num_scv(); ++i) - for(size_t sh = 0 ; sh < scv(i).num_sh(); ++sh) - MatVecMult(m_vSCV[i].vGlobalGrad[sh], m_vSCV[i].JtInv, m_vSCV[i].vLocalGrad[sh]); - -// Copy ip pos in list for SCVF - for(size_t i = 0; i < num_scvf(); ++i) - m_vGlobSCVF_IP[i] = scvf(i).global_ip(); - -// if no boundary subsets required, return - if(num_boundary_subsets() == 0 || ish == NULL) return; - else update_boundary_faces(pElem, vCornerCoords, ish); - - -} - -template -void FV1IBGeometry:: -update_boundary_faces(GridObject* elem, const MathVector* vCornerCoords, const ISubsetHandler* ish) -{ - UG_ASSERT(dynamic_cast(elem) != NULL, "Wrong element type."); - TElem* pElem = static_cast(elem); - -// get grid - Grid& grid = *(ish->grid()); - -// vector of subset indices of side - std::vector vSubsetIndex; - -// get subset indices for sides (i.e. edge in 2d, faces in 3d) - if(dim == 1) { - std::vector vVertex; - CollectVertices(vVertex, grid, pElem); - vSubsetIndex.resize(vVertex.size()); - for(size_t i = 0; i < vVertex.size(); ++i) - vSubsetIndex[i] = ish->get_subset_index(vVertex[i]); - } - if(dim == 2) { - std::vector vEdges; - CollectEdgesSorted(vEdges, grid, pElem); - vSubsetIndex.resize(vEdges.size()); - for(size_t i = 0; i < vEdges.size(); ++i) - vSubsetIndex[i] = ish->get_subset_index(vEdges[i]); - } - if(dim == 3) { - std::vector vFaces; - CollectFacesSorted(vFaces, grid, pElem); - vSubsetIndex.resize(vFaces.size()); - for(size_t i = 0; i < vFaces.size(); ++i) - vSubsetIndex[i] = ish->get_subset_index(vFaces[i]); - } - -// loop requested subset - typename std::map >::iterator it; - for (it=m_mapVectorBF.begin() ; it != m_mapVectorBF.end(); ++it) - { - // get subset index - const int bndIndex = (*it).first; - - // get vector of BF for element - std::vector& vBF = (*it).second; - - // clear vector - vBF.clear(); - - // current number of bf - size_t curr_bf = 0; - - // loop sides of element - for(size_t side = 0; side < vSubsetIndex.size(); ++side) - { - // skip non boundary sides - if(vSubsetIndex[side] != bndIndex) continue; - - // number of corners of side (special case bottom side pyramid) - const int coOfSide = (m_rRefElem.REFERENCE_OBJECT_ID != ROID_PYRAMID || side != 0) - ? m_rRefElem.num(dim-1, side, 0) : m_rRefElem.num(dim-1, side, 0) + 2; - - // resize vector - vBF.resize(curr_bf + coOfSide); - - // loop corners - for(int co = 0; co < coOfSide; ++co) - { - // get current bf - BF& bf = vBF[curr_bf]; - - // set node id == scv this bf belongs to - if (m_rRefElem.REFERENCE_OBJECT_ID != ROID_PYRAMID || side != 0) - bf.nodeId = m_rRefElem.id(dim-1, side, 0, co); - else - { - // map according to order defined in ComputeBFMidID - bf.nodeId = m_rRefElem.id(dim-1, side, 0, (co % 3) + (co>3 ? 1 : 0)); - } - - // Compute MidID for BF - ComputeBFMidID(m_rRefElem, side, bf.vMidID, co); - - // copy corners of bf - CopyCornerByMidID(bf.vLocPos, bf.vMidID, m_vvLocMid, BF::numCo); - CopyCornerByMidID(bf.vGloPos, bf.vMidID, m_vvGloMid, BF::numCo); - - // integration point - AveragePositions(bf.localIP, bf.vLocPos, BF::numCo); - AveragePositions(bf.globalIP, bf.vGloPos, BF::numCo); - - // normal on scvf - traits::NormalOnSCVF(bf.Normal, bf.vGloPos, m_vvGloMid[0]); - - // compute volume - bf.Vol = VecTwoNorm(bf.Normal); - - m_rTrialSpace.shapes(&(bf.vShape[0]), bf.localIP); - m_rTrialSpace.grads(&(bf.vLocalGrad[0]), bf.localIP); - - m_mapping.jacobian_transposed_inverse(bf.JtInv, bf.localIP); - bf.detj = m_mapping.sqrt_gram_det(bf.localIP); - - for(size_t sh = 0 ; sh < bf.num_sh(); ++sh) - MatVecMult(bf.vGlobalGrad[sh], bf.JtInv, bf.vLocalGrad[sh]); - - // increase curr_bf - ++curr_bf; - } - } - } -} - - -//////////////////////////////////////////////////////////////////////////////// -// Dim-dependent Finite Volume Geometry -//////////////////////////////////////////////////////////////////////////////// -template -void DimFV1IBGeometry:: -adapt(GridObject* elem, const MathVector* vCornerCoords, - const ISubsetHandler* ish) -{ - - for(size_t ip = 0; ip < num_scvf(); ++ip) - UG_LOG("Dim- vSCVF_PosOnEdge = " << vSCVF_PosOnEdge[ip] << "\n"); - -// compute global informations for scvf - for(size_t i = 0; i < num_scvf(); ++i) - { - UG_LOG("Dim-ip's: " << m_vSCVF[i].globalIP << "\n"); - UG_LOG("Dim-normals: " << m_vSCVF[i].Normal << "\n"); - - } - -// compute global informations for scvf - for(size_t i = 0; i < num_scvf(); ++i) - { - //VecScaleAdd(m_vSCVF[i].globalIP, vSCVF_PosOnEdge[i], 0.5, m_MidPoint, 0.5); - for(size_t d = 0; d < m_vSCVF[i].globalIP.size(); ++d) - m_vSCVF[i].globalIP[d] = 0.5*(vSCVF_PosOnEdge[i][d] + m_MidPoint[d]); - - //traits::NormalOnSCVF(m_vSCVF[i].Normal, vSCVF_PosOnEdge[i], m_MidPoint); - // 'NormalOnSCVF' braucht Felder im 2. und 3. Parameter - //traits::NormalOnSCVF(m_vSCVF[i].Normal, vSCVF_PosOnEdge, vSCVF_PosOnEdge); - MathVector buffer_comp; - VecSubtract(buffer_comp, vSCVF_PosOnEdge[i], m_MidPoint); - - MathVector buffer_copy; - buffer_copy[0] = -buffer_comp[1]; - buffer_copy[1] = buffer_comp[0]; - - // check the orientation of the newly computet Normal: - // -> has to be in direction from -> to, i.e. VecDot(Normal_alt, Normal_neu) > 0 - if ( VecDot(m_vSCVF[i].Normal, buffer_copy) > 0 ) - { - UG_LOG("Dim-Positiv: normals: " << m_vSCVF[i].Normal << "\n"); - UG_LOG("Dim-Positiv: normals: " << buffer_copy << "\n"); - - m_vSCVF[i].Normal[0] = buffer_copy[0]; - m_vSCVF[i].Normal[1] = buffer_copy[1]; - } - else - { - UG_LOG("Dim-Negativ: normals: " << m_vSCVF[i].Normal << "\n"); - UG_LOG("Dim-Negativ: normals: " << buffer_copy << "\n"); - - m_vSCVF[i].Normal[0] = -buffer_copy[0]; - m_vSCVF[i].Normal[1] = -buffer_copy[1]; - } - - - UG_LOG("Dim-***ip's: " << m_vSCVF[i].globalIP << "\n"); - UG_LOG("Dim-***normals: " << m_vSCVF[i].Normal << "\n"); - UG_LOG("Dim-***buffer_copy: " << buffer_copy << "\n"); - - } - - //UG_THROW("### ok done...\n"); -} - -template -void DimFV1IBGeometry:: -adapt_integration_points(GridObject* elem, const MathVector* vCornerCoords, - const ISubsetHandler* ish) -{ - UG_THROW("adapt_integration_points: ok done...\n"); - -} - -template -void DimFV1IBGeometry:: -adapt_normals(GridObject* elem, const MathVector* vCornerCoords, - const ISubsetHandler* ish) -{ -/// BEACHTE: -/// normal on scvf (points direction "from"->"to") - - - for(size_t i = 0; i < num_scvf(); ++i) - { - UG_LOG("ip's: " << m_vSCVF[i].globalIP << "\n"); - UG_LOG("normals: " << m_vSCVF[i].Normal << "\n"); - - } - - UG_THROW("stop hier...\n"); - - -} - -template -void DimFV1IBGeometry:: -update_local_data() -{ -// get reference element - try{ - const DimReferenceElement& rRefElem - = ReferenceElementProvider::get(m_roid); - -// set corners of element as local centers of nodes - for(size_t i = 0; i < rRefElem.num(0); ++i) - m_vvLocMid[0][i] = rRefElem.corner(i); - -// compute local midpoints - ComputeMidPoints, maxMid> - (rRefElem, m_vvLocMid[0], m_vvLocMid); - -// set number of scvf / scv of this roid - m_numSCV = (m_roid != ROID_PYRAMID) ? rRefElem.num(0) : 8; // number of corners - m_numSCVF = (m_roid != ROID_PYRAMID) ? rRefElem.num(1) : 12; // number of edges - -// set up local informations for SubControlVolumeFaces (scvf) -// each scvf is associated to one edge of the element - for(size_t i = 0; i < num_scvf(); ++i) - { - // this scvf separates the given nodes - if (m_roid != ROID_PYRAMID) - { - m_vSCVF[i].From = rRefElem.id(1, i, 0, 0); - m_vSCVF[i].To = rRefElem.id(1, i, 0, 1); - } - // special case pyramid (scvf not mappable by edges) - else - { - // map according to order defined in ComputeSCVFMidID - m_vSCVF[i].From = ((i>6 && i%3) ? (i%3)+1 : i%3); - m_vSCVF[i].To = i%6 > 2 ? 4 : ((i+1)%3 + (i>5 && i<8 ? 1 : 0)); - } - - - // compute mid ids of the scvf - ComputeSCVFMidID(rRefElem, m_vSCVF[i].vMidID, i); - - // copy local corners of scvf - CopyCornerByMidID(m_vSCVF[i].vLocPos, m_vSCVF[i].vMidID, m_vvLocMid, SCVF::numCo); - - // integration point - AveragePositions(m_vSCVF[i].localIP, m_vSCVF[i].vLocPos, SCVF::numCo); - } - -// set up local informations for SubControlVolumes (scv) -// each scv is associated to one corner of the element - for(size_t i = 0; i < num_scv(); ++i) - { - // store associated node - if (m_roid != ROID_PYRAMID) - { - m_vSCV[i].nodeId = i; - } - // special case pyramid (scv not mappable by corners) - else - { - // map according to order defined in ComputeSCVMidID - m_vSCV[i].nodeId = i<3 ? i : (i<5 ? (i+1)%5 : i-3); - } - - // compute mid ids scv - ComputeSCVMidID(rRefElem, m_vSCV[i].vMidID, i); - - // copy local corners of scv - CopyCornerByMidID(m_vSCV[i].vLocPos, m_vSCV[i].vMidID, m_vvLocMid, m_vSCV[i].num_corners()); - } - - ///////////////////////// - // Shapes and Derivatives - ///////////////////////// - - const LocalShapeFunctionSet& TrialSpace = - LocalFiniteElementProvider::get(m_roid, LFEID(LFEID::LAGRANGE, dim, 1)); - - m_nsh = TrialSpace.num_sh(); - - for(size_t i = 0; i < num_scvf(); ++i) - { - m_vSCVF[i].numSH = TrialSpace.num_sh(); - TrialSpace.shapes(&(m_vSCVF[i].vShape[0]), m_vSCVF[i].localIP); - TrialSpace.grads(&(m_vSCVF[i].vLocalGrad[0]), m_vSCVF[i].localIP); - } - - for(size_t i = 0; i < num_scv(); ++i) - { - m_vSCV[i].numSH = TrialSpace.num_sh(); - TrialSpace.shapes(&(m_vSCV[i].vShape[0]), m_vSCV[i].vLocPos[0]); - TrialSpace.grads(&(m_vSCV[i].vLocalGrad[0]), m_vSCV[i].vLocPos[0]); - } - - } - UG_CATCH_THROW("DimFV1IBGeometry: update failed."); - -// copy ip positions in a list for Sub Control Volumes Faces (SCVF) - for(size_t i = 0; i < num_scvf(); ++i) - m_vLocSCVF_IP[i] = scvf(i).local_ip(); -} - - -/// update data for given element -template -void DimFV1IBGeometry:: -update(GridObject* pElem, const MathVector* vCornerCoords, const ISubsetHandler* ish) -{ -// If already update for this element, do nothing - if(m_pElem == pElem) return; else m_pElem = pElem; - -// refresh local data, if different roid given - if(m_roid != pElem->reference_object_id()) - { - // remember new roid - m_roid = (ReferenceObjectID) pElem->reference_object_id(); - - // update local data - update_local_data(); - } - -// get reference element - try{ - const DimReferenceElement& rRefElem - = ReferenceElementProvider::get(m_roid); - -// remember global position of nodes - for(size_t i = 0; i < rRefElem.num(0); ++i) - m_vvGloMid[0][i] = vCornerCoords[i]; - -// compute local midpoints - ComputeMidPoints, maxMid>(rRefElem, m_vvGloMid[0], m_vvGloMid); - -// compute global informations for scvf - for(size_t i = 0; i < num_scvf(); ++i) - { - // copy local corners of scvf - CopyCornerByMidID(m_vSCVF[i].vGloPos, m_vSCVF[i].vMidID, m_vvGloMid, SCVF::numCo); - - // integration point - AveragePositions(m_vSCVF[i].globalIP, m_vSCVF[i].vGloPos, SCVF::numCo); - - // normal on scvf - traits::NormalOnSCVF(m_vSCVF[i].Normal, m_vSCVF[i].vGloPos, m_vvGloMid[0]); - } - -// compute size of scv - for(size_t i = 0; i < num_scv(); ++i) - { - // copy global corners - CopyCornerByMidID(m_vSCV[i].vGloPos, m_vSCV[i].vMidID, m_vvGloMid, m_vSCV[i].num_corners()); - - // compute volume of scv - m_vSCV[i].Vol = ElementSize(m_vSCV[i].vGloPos); - } - -// get reference mapping - DimReferenceMapping& rMapping = ReferenceMappingProvider::get(m_roid); - rMapping.update(vCornerCoords); - - //\todo compute with on virt. call -// compute jacobian for linear mapping - if(rMapping.is_linear()) - { - MathMatrix JtInv; - rMapping.jacobian_transposed_inverse(JtInv, m_vSCVF[0].local_ip()); - const number detJ = rMapping.sqrt_gram_det(m_vSCVF[0].local_ip()); - - for(size_t i = 0; i < num_scvf(); ++i) - { - m_vSCVF[i].JtInv = JtInv; - m_vSCVF[i].detj = detJ; - } - - for(size_t i = 0; i < num_scv(); ++i) - { - m_vSCV[i].JtInv = JtInv; - m_vSCV[i].detj = detJ; - } - } -// else compute jacobian for each integration point - else - { - for(size_t i = 0; i < num_scvf(); ++i) - { - rMapping.jacobian_transposed_inverse(m_vSCVF[i].JtInv, m_vSCVF[i].local_ip()); - m_vSCVF[i].detj = rMapping.sqrt_gram_det(m_vSCVF[i].local_ip()); - } - for(size_t i = 0; i < num_scv(); ++i) - { - rMapping.jacobian_transposed_inverse(m_vSCV[i].JtInv, m_vSCV[i].local_ip()); - m_vSCV[i].detj = rMapping.sqrt_gram_det(m_vSCV[i].local_ip()); - } - } - -// compute global gradients - for(size_t i = 0; i < num_scvf(); ++i) - for(size_t sh = 0; sh < scvf(i).num_sh(); ++sh) - MatVecMult(m_vSCVF[i].vGlobalGrad[sh], m_vSCVF[i].JtInv, m_vSCVF[i].vLocalGrad[sh]); - - for(size_t i = 0; i < num_scv(); ++i) - for(size_t sh = 0; sh < scv(i).num_sh(); ++sh) - MatVecMult(m_vSCV[i].vGlobalGrad[sh], m_vSCV[i].JtInv, m_vSCV[i].vLocalGrad[sh]); - -// copy ip points in list (SCVF) - for(size_t i = 0; i < num_scvf(); ++i) - m_vGlobSCVF_IP[i] = scvf(i).global_ip(); - - } - UG_CATCH_THROW("DimFV1IBGeometry: update failed."); - -// if no boundary subsets required, return - if(num_boundary_subsets() == 0 || ish == NULL) return; - else update_boundary_faces(pElem, vCornerCoords, ish); -} - -template -void DimFV1IBGeometry:: -update_boundary_faces(GridObject* pElem, const MathVector* vCornerCoords, const ISubsetHandler* ish) -{ -// get grid - Grid& grid = *(ish->grid()); - -// vector of subset indices of side - std::vector vSubsetIndex; - -// get subset indices for sides (i.e. edge in 2d, faces in 3d) - if(dim == 1) { - std::vector vVertex; - CollectVertices(vVertex, grid, pElem); - vSubsetIndex.resize(vVertex.size()); - for(size_t i = 0; i < vVertex.size(); ++i) - vSubsetIndex[i] = ish->get_subset_index(vVertex[i]); - } - if(dim == 2) { - std::vector vEdges; - CollectEdgesSorted(vEdges, grid, pElem); - vSubsetIndex.resize(vEdges.size()); - for(size_t i = 0; i < vEdges.size(); ++i) - vSubsetIndex[i] = ish->get_subset_index(vEdges[i]); - } - if(dim == 3) { - std::vector vFaces; - CollectFacesSorted(vFaces, grid, pElem); - vSubsetIndex.resize(vFaces.size()); - for(size_t i = 0; i < vFaces.size(); ++i) - vSubsetIndex[i] = ish->get_subset_index(vFaces[i]); - } - - try{ - const DimReferenceElement& rRefElem - = ReferenceElementProvider::get(m_roid); - - DimReferenceMapping& rMapping = ReferenceMappingProvider::get(m_roid); - rMapping.update(vCornerCoords); - - const LocalShapeFunctionSet& TrialSpace = - LocalFiniteElementProvider::get(m_roid, LFEID(LFEID::LAGRANGE, dim, 1)); - -// loop requested subset - typename std::map >::iterator it; - for (it=m_mapVectorBF.begin() ; it != m_mapVectorBF.end(); ++it) - { - // get subset index - const int bndIndex = (*it).first; - - // get vector of BF for element - std::vector& vBF = (*it).second; - - // clear vector - vBF.clear(); - - // current number of bf - size_t curr_bf = 0; - - // loop sides of element - for(size_t side = 0; side < vSubsetIndex.size(); ++side) - { - // skip non boundary sides - if(vSubsetIndex[side] != bndIndex) continue; - - // number of corners of side (special case bottom side pyramid) - const int coOfSide = (pElem->reference_object_id() != ROID_PYRAMID || side != 0) - ? rRefElem.num(dim-1, side, 0) : rRefElem.num(dim-1, side, 0) + 2; - // resize vector - vBF.resize(curr_bf + coOfSide); - - // loop corners - for(int co = 0; co < coOfSide; ++co) - { - // get current bf - BF& bf = vBF[curr_bf]; - - // set node id == scv this bf belongs to - if (pElem->reference_object_id() != ROID_PYRAMID || side != 0) - bf.nodeId = rRefElem.id(dim-1, side, 0, co); - else - { - // map according to order defined in ComputeBFMidID - bf.nodeId = rRefElem.id(dim-1, side, 0, (co % 3) + (co>3 ? 1 : 0)); - } - - // Compute MidID for BF - ComputeBFMidID(rRefElem, side, bf.vMidID, co); - - // copy corners of bf - CopyCornerByMidID(bf.vLocPos, bf.vMidID, m_vvLocMid, BF::numCo); - CopyCornerByMidID(bf.vGloPos, bf.vMidID, m_vvGloMid, BF::numCo); - - // integration point - AveragePositions(bf.localIP, bf.vLocPos, BF::numCo); - AveragePositions(bf.globalIP, bf.vGloPos, BF::numCo); - - // normal on scvf - traits::NormalOnSCVF(bf.Normal, bf.vGloPos, m_vvGloMid[0]); - - // compute volume - bf.Vol = VecTwoNorm(bf.Normal); - - // compute shapes and grads - bf.numSH = TrialSpace.num_sh(); - TrialSpace.shapes(&(bf.vShape[0]), bf.localIP); - TrialSpace.grads(&(bf.vLocalGrad[0]), bf.localIP); - - // get reference mapping - rMapping.jacobian_transposed_inverse(bf.JtInv, bf.localIP); - bf.detj = rMapping.sqrt_gram_det(bf.localIP); - - // compute global gradients - for(size_t sh = 0 ; sh < bf.num_sh(); ++sh) - MatVecMult(bf.vGlobalGrad[sh], bf.JtInv, bf.vLocalGrad[sh]); - - // increase curr_bf - ++curr_bf; - } - } - } - - } - UG_CATCH_THROW("DimFV1IBGeometry: update failed."); -} - -////////////////////// -// FV1IBGeometry - -template class FV1IBGeometry; -template class FV1IBGeometry; -template class FV1IBGeometry; - -template class FV1IBGeometry; -template class FV1IBGeometry; - -template class FV1IBGeometry; -template class FV1IBGeometry; - -template class FV1IBGeometry; -template class FV1IBGeometry; -template class FV1IBGeometry; -template class FV1IBGeometry; - - - -////////////////////// -// DimFV1IBGeometry -template class DimFV1IBGeometry<1, 1>; -template class DimFV1IBGeometry<1, 2>; -template class DimFV1IBGeometry<1, 3>; - -template class DimFV1IBGeometry<2, 2>; -template class DimFV1IBGeometry<2, 3>; - -template class DimFV1IBGeometry<3, 3>; - - diff --git a/ugbase/lib_disc/spatial_disc/domain_disc_impl.h b/ugbase/lib_disc/spatial_disc/domain_disc_impl.h index db696ea59..5912d6100 100644 --- a/ugbase/lib_disc/spatial_disc/domain_disc_impl.h +++ b/ugbase/lib_disc/spatial_disc/domain_disc_impl.h @@ -482,6 +482,10 @@ assemble_jacobian(matrix_type& J, pModifyMemory = u.clone(); pModifyU = pModifyMemory.get(); try{ + m_spAssTuner->modify_GlobalSol(*pModifyMemory, u, dd); + } UG_CATCH_THROW("Cannot modify local solution."); + + try{ for(int type = 1; type < CT_ALL; type = type << 1){ if(!(m_spAssTuner->constraint_type_enabled(type))) continue; for(size_t i = 0; i < m_vConstraint.size(); ++i) @@ -655,6 +659,10 @@ assemble_defect(vector_type& d, pModifyMemory = u.clone(); pModifyU = pModifyMemory.get(); try{ + m_spAssTuner->modify_GlobalSol(*pModifyMemory, u, dd); + } UG_CATCH_THROW("Cannot modify local solution."); + + try{ for(int type = 1; type < CT_ALL; type = type << 1){ if(!(m_spAssTuner->constraint_type_enabled(type))) continue; for(size_t i = 0; i < m_vConstraint.size(); ++i) @@ -1378,6 +1386,10 @@ assemble_jacobian(matrix_type& J, if( m_spAssTuner->modify_solution_enabled() ){ pModifyMemory = vSol->clone(); pModifyU = pModifyMemory; + try{ + m_spAssTuner->modify_GlobalSol(pModifyMemory, vSol, dd); + } UG_CATCH_THROW("Cannot modify local solution."); + try{ for(int type = 1; type < CT_ALL; type = type << 1){ if(!(m_spAssTuner->constraint_type_enabled(type))) continue; @@ -1554,6 +1566,10 @@ assemble_defect(vector_type& d, pModifyMemory = vSol->clone(); pModifyU = pModifyMemory; try{ + m_spAssTuner->modify_GlobalSol(pModifyMemory, vSol, dd); + } UG_CATCH_THROW("Cannot modify local solution."); + + try{ for(int type = 1; type < CT_ALL; type = type << 1){ if(!(m_spAssTuner->constraint_type_enabled(type))) continue; for(size_t i = 0; i < m_vConstraint.size(); ++i) diff --git a/ugbase/lib_disc/spatial_disc/elem_disc/elem_disc_assemble_util.h b/ugbase/lib_disc/spatial_disc/elem_disc/elem_disc_assemble_util.h index 1cb4b8e6e..50c394652 100644 --- a/ugbase/lib_disc/spatial_disc/elem_disc/elem_disc_assemble_util.h +++ b/ugbase/lib_disc/spatial_disc/elem_disc/elem_disc_assemble_util.h @@ -384,6 +384,14 @@ class StdGlobAssembler } UG_CATCH_THROW("(stationary) AssembleJacobian: Cannot prepare element."); + // modifies size of local data (locally) if needed + if( spAssTuner->modify_solution_enabled() ) + { + try{ + spAssTuner->modify_LocalData(locJ, locU, dd); + } UG_CATCH_THROW("Cannot modify local solution."); + } + // reset local algebra locJ = 0.0; @@ -401,6 +409,9 @@ class StdGlobAssembler UG_CATCH_THROW("(stationary) AssembleJacobian: Cannot add local matrix."); } + // ToDO: Only for diffusion, iff INSIDE circle-computation only! ==> all other DoFs set to Dirichlet! + // spAssTuner->adjust_mat_global(J, locJ, dd); + // finish element loop try { @@ -511,6 +522,14 @@ class StdGlobAssembler } UG_CATCH_THROW("(instationary) AssembleJacobian: Cannot prepare element."); + // modifies size of local data (locally) if needed + if( spAssTuner->modify_solution_enabled() ) + { + try{ + spAssTuner->modify_LocalData(locTimeSeries, locJ, locU, dd); + } UG_CATCH_THROW("Cannot modify local solution."); + } + // reset local algebra locJ = 0.0; @@ -635,13 +654,12 @@ class StdGlobAssembler } UG_CATCH_THROW("(stationary) AssembleDefect: Cannot prepare element."); - // ANALOG to 'domain_disc_elem()' - modifies the solution, used - // for computing the defect + // modifies size of local data (locally) if needed if( spAssTuner->modify_solution_enabled() ) { LocalVector& modLocU = locU; try{ - spAssTuner->modify_LocalSol(modLocU, locU, dd); + spAssTuner->modify_LocalData(locD, tmpLocD, locU, dd); } UG_CATCH_THROW("Cannot modify local solution."); // recopy modified LocalVector: @@ -667,13 +685,13 @@ class StdGlobAssembler } UG_CATCH_THROW("(stationary) AssembleDefect: Cannot compute Rhs."); - + // send local to global defect try{ spAssTuner->add_local_vec_to_global(d, locD, dd); } UG_CATCH_THROW("(stationary) AssembleDefect: Cannot add local vector."); - } + } // finish element loop try @@ -684,6 +702,8 @@ class StdGlobAssembler } UG_CATCH_THROW("(stationary) AssembleDefect: Cannot create Data Evaluator."); + + } //////////////////////////////////////////////////////////////////////////////// @@ -781,7 +801,7 @@ class StdGlobAssembler // reset contribution of this element locD = 0.0; - + // loop all time points and assemble them for(size_t t = 0; t < vScaleStiff.size(); ++t) { @@ -798,6 +818,14 @@ class StdGlobAssembler } UG_CATCH_THROW("(instationary) AssembleDefect: Cannot prepare element."); + // modifies size of local data (locally) if needed + if( spAssTuner->modify_solution_enabled() ) + { + try{ + spAssTuner->modify_LocalData(locTimeSeries, locD, tmpLocD, locU, dd, t); + } UG_CATCH_THROW("Cannot modify local solution."); + } + // Assemble M try { @@ -806,7 +834,7 @@ class StdGlobAssembler locD.scale_append(vScaleMass[t], tmpLocD); } UG_CATCH_THROW("(instationary) AssembleDefect: Cannot compute Defect (M)."); - + // Assemble A try { @@ -816,13 +844,11 @@ class StdGlobAssembler Eval.add_def_A_elem(tmpLocD, locU, elem, vCornerCoords, PT_INSTATIONARY); locD.scale_append(scale_stiff, tmpLocD); } - if(t == 0) Eval.add_def_A_elem(locD, locU, elem, vCornerCoords, PT_STATIONARY); } UG_CATCH_THROW("(instationary) AssembleDefect: Cannot compute Defect (A)."); - // Assemble defect for explicit reaction_rate, reaction and source if( t == 1 ) // only valid at lowest timediscretization order { @@ -838,7 +864,6 @@ class StdGlobAssembler locD.scale_append(dt, tmpLocD); } - // Assemble rhs try { diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/Info File 1 b/ugbase/lib_disc/spatial_disc/immersed_util/Info File 1 new file mode 100644 index 000000000..c02b54921 --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/Info File 1 @@ -0,0 +1,175 @@ + +/* Info File for 'ImmersedInterface' class: */ + + +The 'ImmersedInterface' class provides functionality to assemble FE or FV discretisations with immersed interfaces, i.e. boundaries, which are NOT resolved by the given mesh. One possible application is the case, in which the outer boundary of the domain has a special, non-polygonal shape. It is a common approach to embed this into a bigger, regular and polygonal shaped domain. The grid of that domain will contain finite elements, which are cut by the interface. Another application are moving boundaries, where it would be too expensive, to remesh the grid in order to conform the geometry inheriting the moving interface. In all cases, the challenge is to derive a numerical scheme on elements, which are cut by the interface and only a part of the finite elment of the background mesh is relevant for the physical problem. + +There are many methods in the FE and FV community to handle the described case of immersed interfaces and resulting cut finite elements. The CutFEM method (mainly developed by P. Hansbo [1], E. Burman [2]) and also the XFEM method described by Reusken [3] derives a kind of 'ficticious domain method'. It is 'ficticious', since the original shape functions w.r.t. the non-cut domain of the background mesh are used for the discretisation. Appropriate enrichment shape functions are defined on these non-confoming cut elements. In order to compute the physics in the smaller domain cut by the interface, the support of the shape functions gets reduced to the relevant part. +Another strategy is to introduce discontinuous shape functions on the cut elements which provide a jump at the interface and enables to capture jump boundary conditions on the immersed interface. These cathegory of methods was mainly developed for applicaton to crack simulations, see [4]. + +The approach followed by the 'ImmersedInterface' class implementation relies on the idea of the CutFEM or XFEM methods [1]m [2]m [3] and sets up an enriched function space on the cut elements. However, the difference to these methods is to do it in a conforming way: Instead of reducing the support of the 'standard' shape functions (as described above), 'new' shape functions on the cut part of the element are defined which conform the interface. It is simply a conforming finite element space w.r.t. the interface adapted mesh. As consequence, a "virtual" interface-adapted mesh will be used for the discretisation. By means of that enrichment construction, no remeshing will be performed, but the new shape functions are added locally (on the fly during the finite element discretisation) via appropriate adaptations on the cut element. The background mesh remains unchanged. The method is described in [5] and was applied to elliptic problems with discontinuous coefficient [5] and fluid-particle interaction [6], [7]. +In order to enrich the function spaces on the cut elements, certain adaptations within the finite element implementations need to be done. That is described in the following. + +Within the UG4 framework the common strategy of an element based assembling is applied. A loop over all grid elements finally provides the discretisation of the whole domain. In particular, the discretisation is described locally for an arbitrary element and applied in an analogous fashion for each element of the mesh (='ElemDisc' class). All data that needs to be known by the finite element discretisation 'ElemDisc' gets stored in the template class TFVGeom, a so called finite element geometry type. The main and defining ingredient to define and set up the TFVGeom data structure are the corners of an element as input. Derived from that geometrical information such as volume, location of integration points, direction and length of normals, direction and length of gradiens etc. are computed and stored (see ugcore/ugbase/lib_disc/spatial_disc/disc_util for many instantiations of a geometry types). + +In order to provide the enriched local space w.r.t. the cut element as described above, the adaptation is quite simple by means of the described element geometry class TFVGeom. + +The 3 main components are: + +(1) Computation of the intersection points of the immersed interface with the edges of the original element. Those form the NEW corners of the cut element. +(2) Collecting those intersection point and joining them with those original nodes (into a counter-clockwise ording), which lie inside the domain FULLY DEFINE the adapted element to set up the discretisation on the cut element (see drawings below). +(3) Define a mapping for the newly created DoFs (intersection points) from local assembling indices onto global indices of the DoFs. + + + +Original element without interface: 3 corners and standard DoFs, depicted by '*': + + * + / \ + / \ + / \ + / \ + / \ + / \ + / \ +* _____________ * + + +Assume, that an interface cuts the original element, such that it gets devided into the upper triangle (which we define as lying accross the interface, i.e. outside the domain) and the lower quadrilateral (which we define as inside the domain). The two lower corners are still DoFs of the system. In order to describe the cut element, i.e. the quadrilateral, we add the two intersection points as new corners, depicted by '+' and remove the upper corner. +==> inserting those four coordinates into the element geometry class TFVGeom will directly realize the function space on the adapted element. + + - + / \ + /out\ +.....+.....+..... = interface + / \ + / \ + / inside \ + / domain \ +* _____________ * + + +______ + +REMARK: The assembling process will loop over the original triangular element but change the description by means of new corners on the fly! + ==> the grid remains unchanged! +______ + + + +To perform the described adaptations and provide the data for the assembling of the numerical scheme within UG4, the 'ImmersedInterface' class needs to provide the following functionality: + + +(a) Methods to compute the intersection points of the interface with the element edges +(b) Methods to collect all (old + new) corners and provide access +(c) Methods to define new local and global indices of the new DoFs for acces during assembling +(d) Methods to access the cut element data +(e) Methods to hand over these data to the local-to-global mapper +(f) Definition of a mapping of the new local indices/DoFs onto the new OR old global indices/DoFs (depeding on the method: flat top or 2 sided, see (*)). This is done by the local-to-global mapper. For comments on that, see also the 'Info File 2' within this folder and the 'Info File' for the local-to-global mapper. + + +(*) Depending on the choice of the local-to-global mapping (task (3)), the ansatz space on a cut element will differ. In UG4 two different variants are implemented: + +(1) In the 'ImmersedInterfaceDiffusion' derivation of the 'ImmersedInterface' class, all intersection points of a cut element will be maped to individual DoFs. These DoFs need to be created newly into the global algebra, if the algebra does not provide them based on the original (typically smaller dimensional) grid. The resulting ansatz space is a boundary fitted space, which conforms the immersed boundary. Usually, the number of DoFs in the matrix for the jacobian and the vector for the solution and defect needs to be increased. The class provides methods to handle that in an initialisation phase. The resulting ansatz space is a boundary fitted space, which conforms the immersed boundary. + + +(2) In the 'MovingParticle' derivation of the 'ImmersedInterface' class, the intersection points of an element will be mapped onto the original vertex, which lies on the same cut element, but outside the domain (across the interface). In the picture above, the two 'plus'-nodes will be algebraically mapped, i.e. associated, with the 'minus'-node on the triangle. Mathematically, the resulting space is a so called "flat top" space, since it results in piecewise constant solutions along the connecting hyperplane between these intersection points. In the picture below, the two 'plus'-nodes will be algebraically mapped, i.e. associated, with the 'minus'-node on the triangle. + + + + +The 5 main components of the 'ImmersedInterface' class are the following sub classes: + +(I) InterfaceProvider +(II) CutElementHandler, providing (a),(d) +(III) InterfaceHandlerLocal, providing (a), (b), (c) +(IV) LocToGlobMapper, providing (e), (f) +(V) InterfaceBndCond + + + +(I) InterfaceProvider: +The InterfaceProvider simply stores main data defining the interface, such as its location, associated solution values etc. + + +(II) CutElementHandler: +- provides access to InterfaceProvider +- computes global infos about cut elements and global access to that: via the BoolMarker data structure of UG4 + --> BoolMarker provide the boolian whether an element/vertex is cut or non-cut (for more infos se Info File of the CutElementHander) +- computes lists of all cut elements, all outside elemets etc. +- it has NO access to InterfaceHandlerLocal +- the InterfaceHandlerLocal has access to the CutElementHandler + +Important methods: +---> is_onInterfaceVertex(), is_outsideVertex(), is_nearInterfaceVertex() +---> get_intersectionPoint() +---> compute_element_modus() +---> get_element_modus() +---> compute_vertex_modus() +---> get_vertex_modus() + + + +(III) InterfaceHandlerLocal: +- computation of intersection points + --> the computation is induced via the call of 'update_elem()', which itself is controlled by the update functionality of the TFVGeom class for each finite element on which assembling will be done +- defining a local indexing of the new+old DoFs +- has access to CutElementHandler + +Important methods: +---> update_elem() +---> compute_cut_element_data() +---> CollectCorners_...() +---> set_roid_2d/3d() + +Important data: +---> m_vCornerCoords: contains the new and old corners, already orderes appropriately! +---> m_vInterfaceID, m_vNOInterfaceID, v_OriginalCornerID: contains all infos on the local indices + + + +(IV) LocToGlobMapper: +- handles the mapping from the local indices provided by the 'InterfaceHandlerLocal' class to the global indices +- it can also implement boundary conditions via the mapping process if not possible through the class 'InterfaceBndCond' + + +(V) InterfaceBndCond: +- has the 'LocalToGlobalHandler' class as a member +- in analogy to usual ElemDisc classes which implement boundary conditions (such as NeumanBoundary) it handles according boundary conditions on the immersed interface with the data provided by the 'LocalToGlobalHandler' + + + + + + + +[1] Hansbo A., Hansbo P.: + "An unfitted finite element method, based on Nitsche's method, for elliptic interface problems." + Computer Methods in Applied Mechanics and Engineering, 191(47-48), (2002), pp. 5537-5552 + +[2] Burman E., Hansbo P., Larson M. G., Massing A.: + "A cut discontinuous Galerkin method for the Laplace-Beltrami operator." + AIMA Journal of Numerical Analysis, 37, (2017), pp.138-169 + +[3] Kirchhart M., Gross S., Reusken A.: + "Analysis of an XFEM Discretization for Stokes Interface Problems." + SIAM Journal of Scientic Computing, 38(2), (2017), pp. A1019-A1043 + +[4] Belytschko T., Gracie R., Ventura G.: + "A review of extended/generalized finite element methods for material modeling." + Modell Simul Mater Sci Eng, 17(4), (2009) + +[5] Hoellbacher S., Wittum G.: + "A sharp interface method using enriched finite elements for elliptic interface problems." + submitted to Numerische Mathematik + +[6] Hoellbacher S., Wittum G.: + "Rotational test spaces for a fully-implicit FVM and FEM for the DNS of fluid-particle interaction" + Journal of Computational Physics, vol. 393, (2019), pp. 186–213 + open access link: https://authors.elsevier.com/sd/article/S0021999119303298 + DOI: https://doi.org/10.1016/j.jcp.2019.05.004 + +[7] Hoellbacher S., Wittum G.: + "Gradient-consistent enrichment of finite element spaces for the DNS of fluid-particle interaction." + submitted to Jounal of Computational Physics + diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/Info File 2 b/ugbase/lib_disc/spatial_disc/immersed_util/Info File 2 new file mode 100644 index 000000000..9ebb89f5e --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/Info File 2 @@ -0,0 +1,70 @@ +/* Info File on the influence of the local-to-global mapping on the mathematical ansatz space */ + + +Depending on the choice of the local-to-global mapping, the ansatz space on a cut element will differ: +On a cut element, in the first assembling step, local couplings will be computed for ALL the intersection points of the interface with the edges of the cut element. That is, to apply the usual discretisation scheme for the new TFVGeom object. The mapping of these couplings to its associated global indices finally defines the property of the underlying finite element space. In UG4 two different variants are implemented: + + +Case 1: Each coupling is mapped to its own, designated global index, i.e. DoF. The resulting space will be the usual finite element space w.r.t. the interface adaped grid. It contains additional nodes along the interface and (virtually) consists of cut elements and original elements. The resulting ansatz space is a boundary fitted space, which conforms the immersed boundary. + +Case 2: The local coupling of an intersection point is mapped onto the global index of the original node, which lies accross the interface, but on the corner of the same element. The resulting finite element space will potentially be smaller than the one of the cut element, since two and more (in 3d) intersection points can share the same node accross the interface. The resulting space is a so called "flat top" space, since it results in piecewise constant solutions along the connecting hyperplane between these intersection points. In the picture below, the two 'plus'-nodes will be algebraically mapped, i.e. associated, with the 'minus'-node on the triangle. + + + +The 'ParticleMapper' class of the 'MovingParticle' derivation of the 'ImmersedInterface' class, is of type case 2: +It maps all couplings of intersection points to the same translational (and in analogy to the rotational) global index. Therefore, the 'ParticleMapper' is a flat-top mapper. + +In contrast, the 'DiffusionInterfaceMapper' is of type case 1: +In particular, it is a tow-sided mapper (see the depicted two 'configurations' below) and the resulting space is an interface adapted space. + + + + +Original element without interface: 3 corners and standard DoFs, depicted by '*': + + * + / \ + / \ + / \ + / \ + / \ + / \ + / \ +* _____________ * + + +Assume, that an interface cuts the original element, such that it gets devided into the upper triangle (which we define as lying accross the interface, i.e. outside the domain) and the lower quadrilateral (which we define as inside the domain). The two lower corners are still DoFs of the system. In order to describe the cut element, i.e. the quadrilateral, we add the two intersection points as new corners, depicted by '+' and remove the upper corner. +==> inserting those four coordinates into the element geometry class TFVGeom will directly realize the function space on the adapted element. + + + +First configuration of the TWO-SIDED case: + + + - + / \ + /out\ +.....+.....+..... = interface + / \ + / \ + / inside \ + / domain \ +* _____________ * + + + + +Second configuration of the TWO-SIDED case: + + * + / \ + / in\ +.....+.....+..... = interface + / \ + / \ + / outside \ + / domain \ +- _____________ - + + + diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/cut_element_handler/Info File 1 b/ugbase/lib_disc/spatial_disc/immersed_util/cut_element_handler/Info File 1 new file mode 100644 index 000000000..84137733b --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/cut_element_handler/Info File 1 @@ -0,0 +1,102 @@ +/* Info File for 'CutElementHandlerBase' class: */ + + +There are 4 categories of elements --> 'ElementModus': + +- INSIDE_DOM: all vertices lie inside the domain, i.e. 'is_outsideDomain(vrt) = false' +- OUTSIDE_DOM: all vertices lie outside the domain, i.e. 'is_outsideDomain(vrt) = true' +- CUT_BY_INTERFACE: vertices lie inside AND outside the domain +- CUT_BY_2_INTERFACE: vertices lie inside the domain AND outside of two different parts of the domain OR only outside of two different parts of the domain + + +There are 3 categories of vertices --> 'VertexModus': + +- INSIDE: 'is_outsideDomain(vrt) = false' +- OUTSIDE: 'is_outsideDomain(vrt) = true' +- ON_INTERFACE: 'is_nearInterface(vrt) = true' + OR + 'is_outsideDomain(vrt) = true' && vrt lies on an element which is 'CUT_BY_INTERFACE' + + + +The following relations derive from their categorisation: + + ON_INTERFACE is contained in OUTSIDE + + +REMARK 1: Only ON_INTERFACE-vertices, which are 'no'(!) OUTSIDE-vertices count as DoFs of the according domain. + That is the reason, why they are taged separately. + +REMARK 2: The near-interface vertices are a subset of the ON_INTERFACE vertices. They are treated similarly. But since there is no need to compute an intersection point ( the discrete interface is moved onto these points, since the computation of the real cut would result in small cut elements), its distinction via the boolian 'is_nearInterface(vrt)' and the assocated BoolMarker 'm_spNearInterfaceVrtMarker' is provided. + + + +The 3 main methods in the class provide access to the information on the VertexModus: + +- bool is_onInterfaceVertex(Vertex* vrt, size_t vrtIndex) +- bool is_OutsideVertex(Vertex* vrt, size_t vrtIndex) +- bool is_nearInterfaceVertex(Vertex* vrt, size_t vrtIndex) + + +The 'ElementModus' and 'VertexModus' are stored in data for LOCAL and GLOBAL access. + +---> For the LOCAL access and only the element, which is currently assembled: + + 'ElementModus': in 'm_ElementModus' + 'VertexModus': in 'm_vvVertexModus' + + +---> For the GLOBAL access and valid until the interface may change location due to motion: + + 'ElementModus': In the associated 'BoolMarker': + - INSIDE in 'm_spInsideMarker' + - OUTSIDE in 'm_spOutsideMarker' + - CUT_BY_INTERFACE in 'm_spCutMarker' + + 'VertexModus': In the associated 'BoolMarker': + - INSIDE in 'm_spInsideMarker' + - OUTSIDE in 'm_spOutsideMarker' + - ON_INTERFACE in 'm_spInterfaceVrtMarker' + ( - near interface (no distinguished VertexModus) in 'm_spNearInterfaceVrtMarker') + + +For methods, which need to loop over all cut elements, these elements are also stored in according lists: + +- m_vvElemList +- m_vvElemListCut +- m_vvElemListOutside + +REMARK: The first index of the double-vector inherits the level-index in case of a mutigrid mesh. +The second index is simply the counter for the element. + + + +The main methods, which are used for the computation of the cut element data (via 'compute_element_modus()') are: + +- bool is_outsideDomain(Vertex* vrt, const number threshold = 1e-10); +- bool is_nearInterface(Vertex* vrt, const number threshold = 1e-10); +- number get_LSvalue(Vertex* vrt); + +---> They can/need to be implemented differently by the derived class. + + +The method 'init()' initiates the computation of the cut element data: + +- the BoolMarker will be set +- the m_vvElemList-lists will be set + + +Further remarks: + +- It is possible to change the orientation of the interface, via 'set_orientation()'. + => All computations of the cut element data will be switched accordingly + +- for orientation = 1 and a circular interface, the inside of the circle will lie outside the domain + +- For a two-sided interface, i.e. where both parts of the interface are part of the + computational domain, all computations can be done for each orientation once + ( see for example the ImmersedInterfaceDiffusion implementation) + + + + diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/cut_element_handler/Info File 2 b/ugbase/lib_disc/spatial_disc/immersed_util/cut_element_handler/Info File 2 new file mode 100644 index 000000000..84ac265cc --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/cut_element_handler/Info File 2 @@ -0,0 +1,39 @@ +/* Info File for 'CutElementHandler_FlatTop' and 'CutElementHandler_TwoSided' class: */ + +The two derived classes contain additional data: + +- They inherit the special instance 'ParticleProvider' as interface provider. + +- They inherit special methods to acces infos of the according 'InterfaceProvider' class. + +- Since the 'ParticleProvider' can hold many particles, the index of a particle is an additional parameter: + => the element lists get a third index for the particle index: m_vvvElemList + => new methods for access: get_prtIndex() and get_prtIndex(dof) + + + + +Further remarks to 'CutElementHandler_FlatTop' class: + +- The class is member of the 'MovingParticle' class. In a moving particle simulation, the domain of a particle contains arbitrary many vertices, which algebraically act as DoFs. Since the particle only possesses the translational and rotational velocity as parameter, only 3 (for 2 space dimensions) or 6 (for 3 space dimensions) DoFs need to be associated to the particle domain. + +- Beside cut element information, also information on the global indices of those DoFs needs to be computed and provided. + +- During initilisation of the inteface, not only the BoolMarker and element lists are set up, but also the global indices for transVel und rotVel: --> additional method 'update_global_indices()' + +New class member: + 'm_vvvGlobalIndices_linearVel' and 'm_vvvGlobalIndices_linearVel' + + + + +Further remarks to 'CutElementHandler_TwoSided' class: + +- The class is member of the 'ImmersedInterfaceDiffusion' class. For the application of elliptic problems with discontinuous coefficients, the domain on BOTH sides of the interface in part of the physical domain. + +- The cut element assembling process needs to be performed TWICE: + --> first: for orientation = 1 and on the according cut part of the element + --> second: for orientation = -1 and on the according cut part of the element + +New class member: + 'm_MapNearVertices' and 'm_verticesNearPos' \ No newline at end of file diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/cut_element_handler/cut_element_handler.h b/ugbase/lib_disc/spatial_disc/immersed_util/cut_element_handler/cut_element_handler.h new file mode 100644 index 000000000..e4838de7f --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/cut_element_handler/cut_element_handler.h @@ -0,0 +1,863 @@ + +/* + * interface_handler_local.h + * + * Created on: 15.01.2015 + * Author: suze + */ + +#ifndef CUT_ELEMENT_HANDLER_H_ +#define CUT_ELEMENT_HANDLER_H_ + +#include "lib_grid/multi_grid.h" +#include "lib_disc/function_spaces/grid_function.h" +#include "../interface_provider/interface_provider_base.h" +#include "../interface_provider/interface_provider_diffusion.h" +#include "../interface_provider/interface_provider_particle.h" + + +#ifdef UG_PARALLEL +#include "pcl/pcl_communication_structs.h" +#include "pcl/pcl_process_communicator.h" +#endif + +namespace ug{ + +enum ElementModus +{ + INSIDE_DOM = 0, + OUTSIDE_DOM, + CUT_BY_INTERFACE, + CUT_BY_2_INTERFACE +}; + +enum VertexModus +{ + INSIDE = 0, + OUTSIDE, + ON_INTERFACE, +}; + + +template +class ICutElementHandler +{ + /// world Dimension + static const int dim = TWorldDim; + + public: + +/// default constructor: + ICutElementHandler(){}; + +/// destructor + ~ICutElementHandler() {} + +// computes the modus of the element as cut or non-cut (= inside or outside of the domain) + ElementModus compute_element_modus(GridObject* elem) + { UG_THROW("in 'ICutElementHandler::compute_element_modus()': needs to be implemented by derived class!\n");} + +// returns the computed element modus, which is either stored as element bool marker, or locally +// as property of the element + ElementModus get_element_modus(GridObject* elem) + { UG_THROW("in 'ICutElementHandler::get_element_modus()' : needs to be implemented by derived class!\n");} + + +// methods used to get the 'VertexModus' of a vertex +// REMARK: 2 arguments: +// Vertex* vrt: for global acces via BoolMarker +// size_t vrtIndex: for local access via m_vvVertexModus + + bool is_onInterfaceVertex(Vertex* vrt, size_t vrtIndex) + { UG_THROW("in 'ICutElementHandler::is_onInterfaceVertex()': needs to be implemented by derived class!\n");} + + bool is_OutsideVertex(Vertex* vrt, size_t vrtIndex) + { UG_THROW("in 'ICutElementHandler::is_OutsideVertex()': needs to be implemented by derived class!\n");} + + bool is_nearInterfaceVertex(Vertex* vrt, size_t vrtIndex) + { UG_THROW("in 'ICutElementHandler::is_nearInterfaceVertex()': needs to be implemented by derived class!\n");} + + + +}; + +template +class CutElementHandlerBase : public ICutElementHandler +{ + public: + /// world Dimension + static const int dim = TWorldDim; + + /// Type of position coordinates + typedef MathVector position_type; + + /// Type of Position Attachment + typedef Attachment position_attachment_type; + + + /// Type of Accessor to the Position Data Attachment + typedef Grid::VertexAttachmentAccessor position_accessor_type; + + typedef typename domain_traits::grid_base_object grid_base_object; + + /// constructor: + + // REMARK: due to call of the call of the methog 'm_spInterfaceProvider->get_LSvalue_byPosition()', + // the interfaceProvider needs to be specified already by the constructor! + // --> the call of 'get_LSvalue_byPosition()' will be forwarded by 'InterfaceProviderBase' + // to the derived class! + CutElementHandlerBase(SmartPtr mg, SmartPtr > interfaceProvider); + CutElementHandlerBase(SmartPtr mg, SmartPtr > interfaceProvider); + CutElementHandlerBase(SmartPtr mg, SmartPtr > interfaceProvider); + + + /// destructor + virtual ~CutElementHandlerBase() {} + + ////////////////////////////////////////////////////////// + /// init for time dependent update and initialisation: + ////////////////////////////////////////////////////////// + + /// calls 'copy_solution(topLevel) - update_for_multigrid(baseLev-topLev) - update_solution(topLevel)' + template + void init(ConstSmartPtr dd, const int baseLevel, const int topLevel); + + /// sets all BoolMarker and fills the 'm_vvElemList...' + virtual void update_interface_data(ConstSmartPtr dd, const int levIndex); + /// resets all boolmarker of this class; called during update_interface_data(); necessary for time-dependent case + void clear_bool_marker(); + + /// initializes crucial data for all cut element computations + /// especially'ElementModus' and 'VertexModus' categories + virtual void update_multigrid_data(ConstSmartPtr dd, const int levIndex) + { update_interface_data(dd, levIndex); } + + ////////////////////////////////////////////////////////// + /// virtual base class methods: + ////////////////////////////////////////////////////////// + + // basic methods to compute the modus of an element and a vertex: + + /// returns boolian for 'does 'vrt' lie near interface?' + virtual bool is_outsideDomain(Vertex* vrt); + /// returns boolian for 'does 'vrt' lie outside the domain?' + virtual bool is_nearInterface(Vertex* vrt); + + // methods needed during call of 'is_outsideDomain(), 'is_nearInterface()' + // computes the 'level-set' value of a point w.r.t. the interface, in order to + // derive its 'VertexModus', i.e. INSIDE, OUTSIDE, ON_INTERFACE + // --> evaluate the distance between a vrt and the interface + number get_LSvalue(Vertex* vrt) + { return get_LSvalue_byPosition(m_aaPos[vrt]); } + + virtual number get_LSvalue_byPosition(MathVector vrtPos) = 0; + + ////////////////////////////////////////////////////////// + /// (1A) 'compute' and (1B) 'get' the 'ElementModus': + + + // (1A) computes the modus of the element as cut or non-cut + // (= inside or outside of the domain) and marks according BoolMarker + virtual ElementModus compute_element_modus(GridObject* elem); + + // (1B) returns the computed element modus: + // (1) local access by member 'm_elementModus' + // (2) global acces via 'GridObject* elem' as parameter (can be stored using BoolMarker for elements!) + + // (1B)(1) LOCAL access method + ElementModus get_element_modus() { return m_elementModus; } + + // (1B)(2) GLOBAL acces method + ElementModus get_element_modus(GridObject* elem); // --> ToDo: siehe FT impl!! + + + /// checks if cut element data is updated and returns 'levIndex'-pair for 'gridLevel' in 'm_Map' + int get_Index(const GridLevel& gridLevel, ConstSmartPtr dd); + /// only call, when you are sure, that the data is available; if NOT: THROW error! + int get_Index(const GridLevel& gridLevel); + + + ////////////////////////////////////////////////////////////////////////////////// + /// (2A) compute, (2B) get, (C) check the 'VertexModus': + ////////////////////////////////////////////////////////////////////////////////// + + ////////////////////////////////////////////////////////////////////////////////// + // (2A) computes the modus of the vertex as INSIDE, OUTSIDE, ON_INTERFACE + + VertexModus compute_vertex_modus(Vertex* vrt); + + ////////////////////////////////////////////////////////////////////////////////// + // (2B) returns the computed vertex modus: + // --> LOCAL acces (only valid for the currently assembled element!) + check via 'size_t vrtIndex' + VertexModus get_vertex_modus(size_t vrtIndex, const int localInd) + { return m_vvVertexMode[localInd][vrtIndex];} + + bool check_vertex_modus(VertexModus vrtModus, size_t vrtIndex, const int interfaceOrientation) + { + size_t localInd = -0.5*interfaceOrientation + 0.5; + if ( get_vertex_modus(vrtIndex, localInd) == vrtModus ) + return true; + return false; + } + + ////////////////////////////////////////////////////////////////////////////////////////////////////////// + /// (C) base class methods 'is_onInterfaceVertex()', 'is_OutsideVertex()', 'is_nearInterfaceVertex()' + // (C1) global version via 'Vertex* vrt' (i.e. valid during whole assembling process) + // (C2) local version via 'size_t vrtIndex' (i.e. valid only for assembling process on the current element) + // (C3) combined version + + // (C1) global version via 'Vertex* vrt' + bool is_onInterfaceVertex_globalAccess(Vertex* vrt, size_t vrtIndex) + { return m_spInterfaceVrtMarker->is_marked(vrt); } + + bool is_OutsideVertex_globalAccess(Vertex* vrt, size_t vrtIndex) + { return m_spOutsideMarker->is_marked(vrt); } + + bool is_nearInterfaceVertex_globalAccess(Vertex* vrt, size_t vrtIndex) + { return m_spNearInterfaceVrtMarker->is_marked(vrt); } + + // (C2) local version via 'size_t vrtIndex' + bool is_onInterfaceVertex_localAccess(Vertex* vrt, size_t vrtIndex) + { return !check_vertex_modus(INSIDE, vrtIndex, get_orientation()); } + + bool is_OutsideVertex_localAccess(Vertex* vrt, size_t vrtIndex) + { return check_vertex_modus(OUTSIDE, vrtIndex, get_orientation()); } + + bool is_nearInterfaceVertex_localAccess(Vertex* vrt, size_t vrtIndex) + { return check_vertex_modus(ON_INTERFACE, vrtIndex, get_orientation()); } + + // (C3) combined version + bool is_onInterfaceVertex(Vertex* vrt, size_t vrtIndex) + { + if ( !m_bBoolMarkerInit ) return is_onInterfaceVertex_localAccess(vrt, vrtIndex); + else return is_onInterfaceVertex_globalAccess(vrt, vrtIndex); + } + bool is_OutsideVertex(Vertex* vrt, size_t vrtIndex) + { + if ( !m_bBoolMarkerInit ) return is_OutsideVertex_localAccess(vrt, vrtIndex); + else return is_OutsideVertex_globalAccess(vrt, vrtIndex); + } + bool is_nearInterfaceVertex(Vertex* vrt, size_t vrtIndex) + { + if ( !m_bBoolMarkerInit ) return is_nearInterfaceVertex_localAccess(vrt, vrtIndex); + else return is_nearInterfaceVertex_globalAccess(vrt, vrtIndex); + } + + + ////////////////////////////////////////////////////////// + /// further base class methods: + ////////////////////////////////////////////////////////// + + // getter and setter for orientation of interface + void set_orientation(const int orientation) { m_spInterfaceProvider->set_orientation(orientation); } + const int get_orientation() const{ return m_spInterfaceProvider->get_orientation(); } + + // the 'threshold' defines the bandwidth around the immersed interface, in which a node + // counts as 'OUTSIDE' or 'ON_INTERFACE' during call of 'is_outside()', 'is_nearInterface() + void set_threshold(size_t level, const number threshold) + { m_vThresholdOnLevel[level] = threshold; } + + number get_threshold(Vertex* vrt) + { return m_vThresholdOnLevel[m_spMG->get_level(vrt)]; } + + // returns the number of cut Elements on the level 'levIndex': + size_t get_numCutElements(const int levIndex) + { return m_vvElemListCut[levIndex].size(); } + + + /////////////////////////////////////////////////////////////////////// + /// moving interface methods: + /////////////////////////////////////////////////////////////////////// + + // updates the location of the interface in case of a moving interface + // no base implementation provided; dependent on the specific application + void update_interface(const int topLevel, const number deltaT) + { UG_THROW("in 'CutElementHandlerBase::update_interface()': needs to be implemented by derived class!\n");} + + + /////////////////////////////////////////////////////////////////////// + /// class member + /////////////////////////////////////////////////////////////////////// + + + // data for geometric location access of vertices Vertex* vrt + SmartPtr m_spMG; + position_attachment_type m_aPos; /// m_Map; + + /// maximal distance, up to which a node will be couted as 'on interface' + std::vector m_vThresholdOnLevel; + + // data for LOCAL access + ElementModus m_elementModus; + + // indexing: m_vVertexMode[...] = m_vvVertexMode[current Orientation][...] + std::vector m_vVertexMode; + + // indexing: [orientation][VertexModus] + // -> for both orientations of the interface, the cut element + // is one part of the element, inheriting according vertices + // -> their according VertexMode is stored in [][VertexModus] + + std::vector > m_vvVertexMode; + + bool m_bBoolMarkerInit; + + // data for GLOBAL access + // REMARK: for explanation of the different types of vertices, elements see File! + SmartPtr m_spInterfaceVrtMarker; // marks: vertices for 'is_outside() = true' + // AND which lie on a cut element + SmartPtr m_spNearInterfaceVrtMarker; // marks: vertices for 'is_nearInterface() = true' + // i.e. potentially inside domain + SmartPtr m_spCutMarker; // marks: elements, edges, vertices + SmartPtr m_spOutsideMarker; // marks: elements, edges, vertices + // --> for vertices: 'true' for 'is_outside() = true' + // OR 'is_nearInterface() = true' + SmartPtr m_spInsideMarker; // marks: elements, edges, vertices + // --> for vertices: 'true' for 'is_outside() = false' + // ( => is_nearInterface() = false'!) + + + /// element lists computed during 'update_interface_data()' to enable looping over + // distinguished element types, i.e. all, cut elements or outside elements + // indexing: [levIndex][counter] + std::vector > m_vvElemList; + std::vector > m_vvElemListCut; + std::vector > m_vvElemListOutside; + + + /// contains interface infos (like radius, center ...) + SmartPtr > m_spInterfaceProvider; + +}; + + + + +template +class CutElementHandler_FlatTop : public CutElementHandlerBase +{ + + public: + /// world Dimension + static const int dim = TWorldDim; + + /// Type of position coordinates + typedef MathVector position_type; + + /// Type of Position Attachment + typedef Attachment position_attachment_type; + + struct ParticleData { + MathVector center; + MathVector transVel; + MathVector rotVel; + bool valid; + }; + + // struct CombinedParticleData { + // std::vector data; + // }; + typedef std::vector CombinedParticleData; + + + /// Type of Accessor to the Position Data Attachment + typedef Grid::VertexAttachmentAccessor position_accessor_type; + + typedef typename domain_traits::grid_base_object grid_base_object; + + /// list of element needed for looping cut OR all elements of a particle + typedef std::vector > vvElemList; + + /// default constructor: + CutElementHandler_FlatTop(SmartPtr mg, const char* fctNames, + SmartPtr > interfaceProvider); + CutElementHandler_FlatTop(SmartPtr mg, const char* fctNames, + SmartPtr > interfaceProvider); + + /// destructor + virtual ~CutElementHandler_FlatTop() {} + + + //////////////////////////////////////////////////////////////////////////////// + /// methods called during initialisation of the interface: + //////////////////////////////////////////////////////////////////////////////// + + /// initializes crucial data for all cut element computations + /// especially'ElementModus' and 'VertexModus' categories + void update_multigrid_data(ConstSmartPtr dd, const int levIndex); + + /// methods called during 'update_multigrid_data': + + /// sets all BoolMarker and fills the 'm_vvElemList...' + void update_interface_data(ConstSmartPtr dd, const int levIndex); + + /// computes the global indices of the nodes within a particle, where the DoFs of the + // particle velocities will be (algorithmically!) located, i.e. the solution is stored + // --> for the rigid body motion simulation, the DoFs of the particle will be located + // simply in any "unused" = "free" node inside the particle + void update_global_indices(ConstSmartPtr dd, const int levIndex); + + //////////////////////////////////////////////////////////////////////////////// + /// virtual base class methods, needed for all basic computations + //////////////////////////////////////////////////////////////////////////////// + + /// for explanations regarding the relation between near-interface, outside, + /// on-interface: see the File + + /// returns boolian for 'does 'vrt' lie near interface?' + bool is_nearInterface(Vertex* vrt) + { UG_THROW("not implemented, since the alternative method" << + "'is_nearInterface_with_given_index()' is used by this class!\n");} + + // returns boolian for 'is near interface?' for a given 'prtIndex' + bool is_nearInterface_with_given_index(const int prtIndex, Vertex* vrt); + + /// returns boolian for 'does 'vrt' lie outside the domain?' + bool is_outsideDomain(Vertex* vrt) + { return is_outsideFluid(vrt); } + + bool is_outsideFluid(Vertex* vrt); + + // returns boolian for 'is outside?' for a given 'prtIndex' + bool is_insideParticle_with_given_index(const int prtIndex, Vertex* vrt); + + // Remark: not only returns the boolian for 'is outise?', but also writes the + // according 'PrtIndex' into data, in which the 'vrt' is located + bool is_outsideFluid(int& PrtIndex, Vertex* vrt); + + //////////////////////////////////////////////////////////////////////////////// + // methods needed during call of 'is_outsideDomain(), 'is_nearInterface()': + //////////////////////////////////////////////////////////////////////////////// + + // computes the 'level-set' value of a point w.r.t. the interface, in order to + // derive its 'VertexModus', i.e. INSIDE, OUTSIDE, ON_INTERFACE + // --> evaluate the distance between a vrt and the interface + number get_LSvalue_byPosition(MathVector vrtPos) + { return m_spInterfaceProvider->get_LSvalue_byPosition(vrtPos); } + + // new 'get_LSvalue()'-method needed for 'is_outsideDomain()' and 'is_nearInterface()': + // --> with prtIndex as additional parameter compared to base class + number get_LSvalue(Vertex* vrt, const int prtIndex) + { return get_LSvalue_byPosition(this->m_aaPos[vrt], prtIndex); } + + number get_LSvalue_byPosition(MathVector vrtPos, const int prtIndex) + { return m_spInterfaceProvider->get_LSvalue_byPosition(vrtPos, prtIndex);} + + //////////////////////////////////////////////////////////////////////////////// + /// (A) 'compute' and (B) 'get' the 'ElementModus': + //////////////////////////////////////////////////////////////////////////////// + + /// (A) computes the modus of the element as cut or non-cut + /// (= inside or outside of the domain) and marks according BoolMarker + ElementModus compute_element_modus(int prtIndex, GridObject* elem); + ElementModus compute_element_modus(GridObject* elem) + { UG_THROW("Attention: the alternative implementation with additional parameter 'prtIndex' has to be calles!\n"); } + + /// derives the 'ElementModus' from the boolian of the BoolMarker + // => global access to information (not only locally, during assembling + // for that specific 'elem' (see base class for explanation LOCAL, GLOBAL) + ElementModus get_element_modus(GridObject* elem); + + ////////////////////////////////////////////////////////////////////////////////// + /// checks for the 'VertexModus' of a vrt based on the + // --> GLOBAL acces, see comments in base class) + /// --> BoolMarker for global access set during 'update_interface_data()' + + /// returns true, if vertex lies OUTSIDE fluid AND near to interface + bool is_onInterfaceVertex(Vertex* vrt, size_t vrtIndex = 0) + { return this->m_spInterfaceVrtMarker->is_marked(vrt); } + + /// returns true, if vertex lies OUTSIDE fluid => no DoF + bool is_OutsideVertex(Vertex* vrt, size_t vrtIndex = 0) + { return this->m_spOutsideMarker->is_marked(vrt); } + + /// returns true, if vertex lies INSIDE fluid AND near to interface + bool is_nearInterfaceVertex(Vertex* vrt, size_t vrtIndex = 0) + { return this->m_spNearInterfaceVrtMarker->is_marked(vrt); } + + + ///////////////////////////////////////////////////////////////////////////////////////////// + /// methods, which handle the DoFs (and associated global indices) for the particle + /// velocities, which are located in specified grid nodes inside each particle + ///////////////////////////////////////////////////////////////////////////////////////////// + + // checks weather node is transDoF OR rotDoF: + /// returns true, if the local 'dofIndex' of a node of an element, which lies in the particle, + // is one of the selected DoFs for the particle velocities + // => outside domain, but a DoF! + bool is_extraDoF(DoFIndex dofIndex, int levIndex); + + // flags being set during initialisation, which indicate, whether the velocities of a particle + // will be a DoF or not + // --> for simulations of a fixed particle (e.g. cylinder benchmark), the particle velocities are + // not a DoF; + bool get_DoF_modus_linear(int prtIndex) { return m_spInterfaceProvider->get_DoF_modus_linear(prtIndex);} + bool get_DoF_modus_angular(int prtIndex){ return m_spInterfaceProvider->get_DoF_modus_angular(prtIndex);} + + /// Access methods for the global indices of the DoFs of the particle velocities + std::vector get_transInd(int levIndex, int prtIndex) + { + std::vector vTransInd; + for ( size_t cmp = 0; cmp < dim; ++cmp ) + vTransInd.push_back(m_vvvGlobalIndices_linearVel[levIndex][prtIndex][cmp]); + return vTransInd; + } + std::vector get_rotInd(int levIndex, int prtIndex) + { + std::vector vRotInd; + for ( size_t cmp = 0; cmp < dim; ++cmp ) + vRotInd.push_back(m_vvvGlobalIndices_angularVel[levIndex][prtIndex][cmp]); + return vRotInd; + } + + // returns single index for a given velocity component 'cmp' + DoFIndex get_transInd_Comp(int levIndex, int prtIndex, size_t cmp) + { if ( cmp == dim ) UG_THROW("no acces to pressure index in transInd! EXIT...\n"); + return m_vvvGlobalIndices_linearVel[levIndex][prtIndex][cmp]; } + DoFIndex get_rotInd_Comp(int levIndex, int prtIndex, size_t cmp) + { if ( cmp == dim ) UG_THROW("no acces to pressure index in rotInd! EXIT...\n"); + return m_vvvGlobalIndices_angularVel[levIndex][prtIndex][cmp]; } + + // returns all indices for transVel and rotVel + void get_global_indices(std::vector& transInd, std::vector& rotInd, + const int levIndex, const int prtIndex) + { + transInd = get_transInd(levIndex, prtIndex); + rotInd = get_rotInd(levIndex, prtIndex); + } + + // writes the solution of the particle velocities into the data storage provided in the + // 'ParticleProvider' called during PartcleMapper::modify_GlobalSol(): + void set_extraSolTrans(number solution, size_t prtIndex, int timeSeriesInd, int cmp) + { m_spInterfaceProvider->set_linear_velocity(solution, prtIndex, timeSeriesInd, cmp); } + void set_extraSolTrans(MathVector solution, size_t prtIndex, int timeSeriesInd) + { m_spInterfaceProvider->set_linear_velocity(solution, prtIndex, timeSeriesInd); } + void set_extraSolRot(number solution, size_t prtIndex, int timeSeriesInd, int cmp) + { m_spInterfaceProvider->set_angular_velocity(solution, prtIndex, timeSeriesInd, cmp); } + void set_extraSolRot(MathVector solution, size_t prtIndex, int timeSeriesInd) + { m_spInterfaceProvider->set_angular_velocity(solution, prtIndex, timeSeriesInd); } + + /// get solution values + MathVector get_transSol(size_t prtIndex, size_t timeSeriesInd) + { return m_spInterfaceProvider->get_linear_velocity(prtIndex, timeSeriesInd); } + MathVector get_rotSol(size_t prtIndex, size_t timeSeriesInd) + { return m_spInterfaceProvider->get_angular_velocity(prtIndex, timeSeriesInd); } + + // returns the rotation matrix associated with the radial vector + MathMatrix get_rotationMat(MathVector radialVector); + + + ///////////////////////////////////////////////////////////////////////////////////////////// + /// some functionality forwarded to the 'ParticleProvider' for according computations + ///////////////////////////////////////////////////////////////////////////////////////////// + + size_t num_particles() const { return m_spInterfaceProvider->num_particles();} + number get_density(int prtIndex) { return m_spInterfaceProvider->get_density(prtIndex);} + MathVector get_center(int prtIndex){ return m_spInterfaceProvider->get_center(prtIndex);} + void set_center(MathVector center, int prtIndex){ m_spInterfaceProvider->set_center(center, prtIndex);} + number get_radius(int prtIndex) { return m_spInterfaceProvider->get_radius(prtIndex);} + + /// methods called by local-to-global-mapper 'ParticleMapper': + number Volume(int levIndex, size_t prtIndex) + { return m_spInterfaceProvider->Volume(levIndex, prtIndex);} + number Mass(const int levIndex, const int prtIndex, const number fluidDensity) + { return m_spInterfaceProvider->Mass(levIndex, prtIndex, fluidDensity);} + number Mass(const int levIndex, const int prtIndex, const number volume, const number fluidDensity) + { return m_spInterfaceProvider->Mass(levIndex, prtIndex, volume, fluidDensity);} + number MomOfInertia(const int levIndex, const int prtIndex, const number fluidDensity) + { return m_spInterfaceProvider->MomOfInertia(levIndex, prtIndex, fluidDensity);} + number MomOfInertia(const int levIndex, const int prtIndex, const number volume, const number fluidDensity) + { return m_spInterfaceProvider->MomOfInertia(levIndex, prtIndex, volume, fluidDensity);} + + + ////////////////////////////////////////////////////////////////////////////////// + /// furhter functionality + ////////////////////////////////////////////////////////////////////////////////// + + /// for moving interfaces, the location needs to be updated + void update_interface(const int topLevel, const number deltaT) + { update_prtCoords(topLevel, deltaT); } + + void update_prtCoords(const int topLevel, const number deltaT); + + // computes the intersection point of the interface with an edge of the cut element + bool get_intersection_point(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, const int PrtIndex) + { return this->m_spInterfaceProvider->get_intersection_point(Intersect, vrtPosOut, vrtPosIn, PrtIndex); } + bool get_intersection_point(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, const int PrtIndex, std::vector& alphaOut) + { return this->m_spInterfaceProvider->get_intersection_point(Intersect, vrtPosOut, vrtPosIn, PrtIndex, alphaOut); } + + + // getter and setter for the index of the particle, cutting the current element + void set_prtIndex(const int prtIndex) { m_spInterfaceProvider->set_prtIndex(prtIndex); } + const int get_prtIndex() const { return m_spInterfaceProvider->get_prtIndex(); } + int get_prtIndex(size_t dof) + { + UG_THROW("attention: You want to get the particle index of an array. Make sure that the data was set!\n"); + return m_vPrtIndex[dof]; + } + + // called during update_elem() in InterfaceHandler + void compute_and_set_prtIndex(GridObject* elem); + + /// returns true, if 'elem' is a pyramid; used for setting the BoolMarker appropriately + bool element_is_pyramid(grid_base_object* elem); + + + ///////////////////////////////////////////////////////////////////////////////////////////// + // output + ///////////////////////////////////////////////////////////////////////////////////////////// + + /// writes particle velocities into a file -> lua-call + void print_velocity(const MathVector& transSol, const MathVector& rotSol, const int prtIndex, + const bool isTimedep, const number time, const char* filename) + { m_spInterfaceProvider->print_velocity(transSol, rotSol, prtIndex, isTimedep, time, filename); } + + void print_elem_lists(ConstSmartPtr dd); + + // returns the number of cut Elements on the level 'levIndex': + size_t get_numCutElements( const int levIndex, const size_t prtIndex) + { return m_vvvElemListCut[levIndex][prtIndex].size(); } + + ///////////////////////////////////////////////////////////////////////////////////////////// + /// methods for parallel computations + ///////////////////////////////////////////////////////////////////////////////////////////// + + void set_mpi_routine(int val) + { active_mpi_routine = val; } + +#ifdef UG_PARALLEL + void synchronize_particles(int levIndex); +#endif +/* + bool valid_prt_information(int prtIndex) + { return particleData[prtIndex].valid; } +*/ + + ////////////////////////////////////////////////////////// + /// class member + ////////////////////////////////////////////////////////// + + const char* m_fctNames; + + //ToDo:brauche ich das?? + std::vector m_vPrtIndex; + + /// global indices of the DoFs for the particle velocities + /// indexing: [levIndex][prtIndex][cmp] + std::vector< std::vector< std::vector > > m_vvvGlobalIndices_linearVel; + std::vector< std::vector< std::vector > > m_vvvGlobalIndices_angularVel; + + /// element lists computed during 'update_interface_data()' to enable looping over + // distinguished element types, i.e. all, cut elements or outside elements + /// indexing: [levIndex][prtIndex][counter] + std::vector m_vvvElemList; + std::vector m_vvvElemListCut; + std::vector m_vvvElemListOutside; + + /// contains radius, center and density of all given particles + SmartPtr > m_spInterfaceProvider; + + + // CombinedParticleData particleData; + std::size_t active_mpi_routine; + + std::map m_vPrtIndices; + +}; + + + + +template +class CutElementHandler_TwoSided : public CutElementHandlerBase +{ + + public: + /// world Dimension + static const int dim = TWorldDim; + + /// Type of position coordinates + typedef MathVector position_type; + + /// Type of Position Attachment + typedef Attachment position_attachment_type; + + /// Type of Accessor to the Position Data Attachment + typedef Grid::VertexAttachmentAccessor position_accessor_type; + + typedef typename domain_traits::grid_base_object grid_base_object; + + /// list of element needed for looping cut OR all elements of a particle + typedef std::vector > vvElemList; + + /// default constructor: + CutElementHandler_TwoSided(SmartPtr mg, const char* fctNames, + SmartPtr > interfaceProvider); + + /// destructor + virtual ~CutElementHandler_TwoSided() {} + + + //////////////////////////////////////////////////////////////////////////////// + /// virtual base class methods, needed for all basic computations + //////////////////////////////////////////////////////////////////////////////// + + /// for explanations regarding the relation between near-interface, outside, + /// on interface: see the 'Info File 1' + + /// returns boolian for 'does 'vrt' lie near interface?' + bool is_nearInterface(Vertex* vrt); + + /// returns boolian for 'does 'vrt' lie outside the domain?' + bool is_outsideDomain(Vertex* vrt); + + // Remark: not only returns the boolian for 'is outise?', but also writes the + // according 'PrtIndex' into data, in which the 'vrt' is located + bool is_outsideDomain(int& PrtIndex, Vertex* vrt); + + + //////////////////////////////////////////////////////////////////////////////// + // methods needed during call of 'is_outsideDomain(), 'is_nearInterface()': + //////////////////////////////////////////////////////////////////////////////// + + // computes the 'level-set' value of a point w.r.t. the interface, in order to + // derive its 'VertexModus', i.e. INSIDE, OUTSIDE, ON_INTERFACE + // --> evaluate the distance between a vrt and the interface + number get_LSvalue_byPosition(MathVector vrtPos) + { return m_spInterfaceProvider->get_LSvalue_byPosition(vrtPos); } + + // new 'get_LSvalue()'-method needed for 'is_outsideDomain()' and 'is_nearInterface()': + // --> with prtIndex as parameter + number get_LSvalue(Vertex* vrt, const int prtIndex) + { return get_LSvalue_byPosition(this->m_aaPos[vrt], prtIndex); } + + number get_LSvalue_byPosition(MathVector vrtPos, const int prtIndex) + { return m_spInterfaceProvider->get_LSvalue_byPosition(vrtPos, prtIndex);} + + + //////////////////////////////////////////////////////////////////////////////////////// + /// checks for the 'VertexModus' of a vrt + //////////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////////////// + /// REMARK: We can NOT use the BoolMarker for the methods 'is_onInterfaceVertex()', + /// 'is_OutsideVertex(), and 'is_nearInterfaceVertex()', since for the + /// two-sided case, they will be overwritten after switch to the other + /// orientation of the interface + // => LOCAL acces, as specified in the base class, see comments there! + //////////////////////////////////////////////////////////////////////////////////////// + + /// returns true, if vertex lies OUTSIDE fluid AND near to interface + bool is_onInterfaceVertex(Vertex* vrt, size_t vrtIndex) + { return !check_vertex_modus(INSIDE, vrtIndex, this->get_orientation()); } + + /// returns true, if vertex lies OUTSIDE fluid => no DoF + bool is_OutsideVertex(Vertex* vrt, size_t vrtIndex) + { return check_vertex_modus(OUTSIDE, vrtIndex, this->get_orientation()); } + + /// returns true, if vertex lies INSIDE fluid AND near to interface + bool is_nearInterfaceVertex(Vertex* vrt, size_t vrtIndex) + { return check_vertex_modus(ON_INTERFACE, vrtIndex, this->get_orientation()); } + + ////////////////////////////////////////////////////////////////////////// + /// access methods for the 'VertexModus' WITHOUT 'Vertex'-Parameter: + // --> needed for access during loc_to_glob_mapper! + + VertexModus get_vertex_modus(size_t vrtIndex, const int localind) { return this->m_vvVertexMode[localind][vrtIndex];} + + /// returns true, if vertex lies INSIDE fluid and near to interface => no DoF + bool check_vertex_modus(VertexModus vrtModus, size_t vrtIndex, const int interfaceOrientation) + { + size_t localInd = -0.5*interfaceOrientation + 0.5; + if ( get_vertex_modus(vrtIndex, localInd) == vrtModus ) + return true; + return false; + } + + + /////////////////////////////////////////////////////////////////////////////////////// + /// further getter and setter methods + /////////////////////////////////////////////////////////////////////////////////////// + + // getter and setter for prtIndex of the particle, cutting the current element + void set_prtIndex(const int prtIndex) { m_spInterfaceProvider->set_prtIndex(prtIndex); } + const int get_prtIndex() const{ return m_spInterfaceProvider->get_prtIndex(); } + + int get_prtIndex(size_t dof) + { + UG_THROW("attention: You want to get the particle index of an array. Make sure that the data was set!\n"); + return m_vPrtIndex[dof]; + } + + // called during update_elem() in InterfaceHandler + void compute_and_set_prtIndex(GridObject* elem); + + size_t get_or_insert_vertex_near(const MathVector& vrtPos); + const size_t get_numNearVerticesPos() const { return m_verticesNearPos.size(); } + + // ToDo: 'm_bElementNearInterface' und method brauche ich nicht mehr! + bool is_element_near_interface() { return m_bElementNearInterface;} + + + ///////////////////////////////////////////////////////////////////////////////////////////// + /// some functionality forwarded to the 'ParticleProvider' for according computations + ///////////////////////////////////////////////////////////////////////////////////////////// + + size_t num_particles() const { return m_spInterfaceProvider->num_particles();} + number get_theta(int prtIndex) { return m_spInterfaceProvider->get_theta(prtIndex);} + number get_density(int prtIndex) { return m_spInterfaceProvider->get_density(prtIndex);} + MathVector get_center(int prtIndex) { return m_spInterfaceProvider->get_center(prtIndex);} + + ///////////////////////////////////////////////////////////////////////////////////////////// + // output + ///////////////////////////////////////////////////////////////////////////////////////////// + + /// writes particle velocities into a file -> lua-call + + + void print_velocity(const MathVector& transSol, const MathVector& rotSol, const int prtIndex, + const bool isTimedep, const number time, const char* filename) + { m_spInterfaceProvider->print_velocity(transSol, rotSol, prtIndex, isTimedep, time, filename); } + + ////////////////////////////////////////////////////////// + /// class member + ////////////////////////////////////////////////////////// + + //ToDo:brauche ich das?? + std::vector m_vPrtIndex; + + std::map m_vPrtIndices; + + + /// element lists computed during 'update_interface_data()' to enable looping over + // distinguished element types, i.e. all, cut elements or outside elements + /// indexing: [levIndex][prtIndex][counter] + std::vector m_vvvElemList; + std::vector m_vvvElemListCut; + std::vector m_vvvElemListOutside; + + /// contains radius, center and density of all given particles + SmartPtr > m_spInterfaceProvider; + + + bool m_bElementNearInterface; + std::map, size_t> m_MapNearVertices; + std::vector > m_verticesNearPos; + + +}; + +}// end namespace ug + +#include "cut_element_handler_base_impl.h" +#include "cut_element_handler_flat_top_impl.h" +#include "cut_element_handler_two_sided_impl.h" + + +#endif /* CUT_ELEMENT_HANDLER_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/cut_element_handler/cut_element_handler_base_impl.h b/ugbase/lib_disc/spatial_disc/immersed_util/cut_element_handler/cut_element_handler_base_impl.h new file mode 100644 index 000000000..d721aaee9 --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/cut_element_handler/cut_element_handler_base_impl.h @@ -0,0 +1,477 @@ +/* + * interface_handler_local_impl.h + * + * Created on: 19.01.2015 + * Author: suze + */ + +#ifndef CUT_ELEMENT_HANDLER_BASE_IMPL_H_ +#define CUT_ELEMENT_HANDLER_BASE_IMPL_H_ + + +namespace ug{ + +template +CutElementHandlerBase:: +CutElementHandlerBase(SmartPtr mg, + SmartPtr > interfaceProvider) + : m_spMG(mg), + m_elementModus(INSIDE_DOM), + m_bBoolMarkerInit(false), + m_spInterfaceProvider((SmartPtr >) interfaceProvider) +{ + + m_vvVertexMode.resize(2); + m_vThresholdOnLevel.resize(mg->num_levels(), 1e-10); + + m_vvVertexMode.clear(); + + // get position attachment + m_aPos = GetDefaultPositionAttachment(); + + // let position accessor access Vertex Coordinates + if(!m_spMG->has_attachment(m_aPos)) + m_spMG->attach_to(m_aPos); + m_aaPos.access(*m_spMG, m_aPos); + + + // initialize data + m_spCutMarker = make_sp(new BoolMarker); + m_spOutsideMarker = make_sp(new BoolMarker); + m_spInsideMarker = make_sp(new BoolMarker); + m_spInterfaceVrtMarker = make_sp(new BoolMarker); + m_spNearInterfaceVrtMarker = make_sp(new BoolMarker); + + m_spCutMarker->assign_grid(*m_spMG); + m_spOutsideMarker->assign_grid(*m_spMG); + m_spInsideMarker->assign_grid(*m_spMG); + m_spInterfaceVrtMarker->assign_grid(*m_spMG); + m_spNearInterfaceVrtMarker->assign_grid(*m_spMG); + + m_spCutMarker->enable_mark_inheritance(false); + m_spOutsideMarker->enable_mark_inheritance(false); + m_spInsideMarker->assign_grid(*m_spMG); + m_spInterfaceVrtMarker->enable_mark_inheritance(false); + m_spNearInterfaceVrtMarker->enable_mark_inheritance(false); + + UG_LOG("init bool_marker done!\n"); + +} + +template +CutElementHandlerBase:: +CutElementHandlerBase(SmartPtr mg, + SmartPtr > interfaceProvider) + : m_spMG(mg), + m_elementModus(INSIDE_DOM), + m_bBoolMarkerInit(false), + m_spInterfaceProvider((SmartPtr >) interfaceProvider) +{ + + m_vvVertexMode.resize(2); + m_vThresholdOnLevel.resize(mg->num_levels(), 1e-10); + + m_vvVertexMode.clear(); + + // get position attachment + m_aPos = GetDefaultPositionAttachment(); + + // let position accessor access Vertex Coordinates + if(!m_spMG->has_attachment(m_aPos)) + m_spMG->attach_to(m_aPos); + m_aaPos.access(*m_spMG, m_aPos); + + + // initialize data + m_spCutMarker = make_sp(new BoolMarker); + m_spOutsideMarker = make_sp(new BoolMarker); + m_spInsideMarker = make_sp(new BoolMarker); + m_spInterfaceVrtMarker = make_sp(new BoolMarker); + m_spNearInterfaceVrtMarker = make_sp(new BoolMarker); + + m_spCutMarker->assign_grid(*m_spMG); + m_spOutsideMarker->assign_grid(*m_spMG); + m_spInsideMarker->assign_grid(*m_spMG); + m_spInterfaceVrtMarker->assign_grid(*m_spMG); + m_spNearInterfaceVrtMarker->assign_grid(*m_spMG); + + m_spCutMarker->enable_mark_inheritance(false); + m_spOutsideMarker->enable_mark_inheritance(false); + m_spInsideMarker->assign_grid(*m_spMG); + m_spInterfaceVrtMarker->enable_mark_inheritance(false); + m_spNearInterfaceVrtMarker->enable_mark_inheritance(false); + + UG_LOG("init bool_marker done!\n"); + + } + +template +CutElementHandlerBase:: +CutElementHandlerBase(SmartPtr mg, + SmartPtr > interfaceProvider) + : m_spMG(mg), + m_elementModus(INSIDE_DOM), + m_bBoolMarkerInit(false), + m_spInterfaceProvider((SmartPtr >) interfaceProvider) +{ + + m_vvVertexMode.resize(2); + m_vThresholdOnLevel.resize(mg->num_levels(), 1e-10); + + m_vvVertexMode.clear(); + + // get position attachment + m_aPos = GetDefaultPositionAttachment(); + + // let position accessor access Vertex Coordinates + if(!m_spMG->has_attachment(m_aPos)) + m_spMG->attach_to(m_aPos); + m_aaPos.access(*m_spMG, m_aPos); + + + // initialize data + m_spCutMarker = make_sp(new BoolMarker); + m_spOutsideMarker = make_sp(new BoolMarker); + m_spInsideMarker = make_sp(new BoolMarker); + m_spInterfaceVrtMarker = make_sp(new BoolMarker); + m_spNearInterfaceVrtMarker = make_sp(new BoolMarker); + + m_spCutMarker->assign_grid(*m_spMG); + m_spOutsideMarker->assign_grid(*m_spMG); + m_spInsideMarker->assign_grid(*m_spMG); + m_spInterfaceVrtMarker->assign_grid(*m_spMG); + m_spNearInterfaceVrtMarker->assign_grid(*m_spMG); + + m_spCutMarker->enable_mark_inheritance(false); + m_spOutsideMarker->enable_mark_inheritance(false); + m_spInsideMarker->enable_mark_inheritance(false); + m_spInterfaceVrtMarker->enable_mark_inheritance(false); + m_spNearInterfaceVrtMarker->enable_mark_inheritance(false); + + clear_bool_marker(); + + UG_LOG("CutElementHandlerBase constructor done!\n"); + +} + + +template +template +void CutElementHandlerBase:: +init(ConstSmartPtr dd, const int baseLevel, const int topLevel) +{ +// clear all marks in grid + clear_bool_marker(); + +// clear data associated to gridlevel + m_Map.clear(); + +// update cut element data + const int levIndex = get_Index(GridLevel(topLevel, GridLevel::LEVEL), dd); + update_multigrid_data(dd, levIndex); + +} + + +template +int CutElementHandlerBase:: +get_Index(const GridLevel& gridLevel, ConstSmartPtr dd) +{ + std::pair::iterator,bool> ret; + ret = m_Map.insert ( std::pair(gridLevel,m_Map.size()) ); + + if (ret.second==false) { + // std::cout << "element already existed"; + // std::cout << " with a value of " << ret.first->second << '\n'; + } + else{ + update_multigrid_data(dd, ret.first->second); + } + + return ret.first->second; +} + +template +int CutElementHandlerBase:: +get_Index(const GridLevel& gridLevel) +{ + std::map::iterator it; + it = m_Map.find(gridLevel); + // if NO element is found for the key 'gridLevel', the iterator points to the end: + if (it == m_Map.end()) + UG_THROW("in CutElementHandler_FlatTop::get_Index(): no data available on gridLevel " << gridLevel << "!\n"); + + return it->second; +} + + + +template +bool CutElementHandlerBase:: +is_nearInterface(Vertex* vrt) +{ +// get threshold (either default = 1e-10 or set by user via .lua-call: + const number threshold = get_threshold(vrt); + +// compute the distance between the location of vrt and the interface: +// level set value: LS_value := radius - distance + const number LS_value = get_LSvalue(vrt); + + if (fabs(LS_value) < threshold) + return true; + + return false; +} + +template +bool CutElementHandlerBase:: +is_outsideDomain(Vertex* vrt) +{ +// get data + const int orientation = get_orientation(); + +// get threshold (either default = 1e-10 or set by user via .lua-call: + const number threshold = get_threshold(vrt); + +// compute the distance between the location of vrt and the interface: +// level set value: LS_value := radius - distance + const number LS_value = get_LSvalue(vrt); + +// a vertex is considered outside, if: +// (A) it lies accross the interface OR +// (B) it lies near to it according to either side +// check (A) + if ( LS_value > threshold && orientation == 1 ) + return true; +// check (A) + else if ( LS_value < -threshold && orientation == -1 ) + return true; +// check (B) + else if ( is_nearInterface(vrt) ) + return true; + + + return false; +} + + +template +ElementModus CutElementHandlerBase:: +get_element_modus(GridObject* elem) // --> ToDo: siehe FT impl!! +{ + if ( !m_bBoolMarkerInit ) + UG_THROW("global element modus not initialized! Call the method update_interface_data()'\n"); + if ( m_spCutMarker->is_marked(elem) ) + { + return CUT_BY_INTERFACE; + } + else if ( m_spOutsideMarker->is_marked(elem) ) + { + return OUTSIDE_DOM; + } + else + return INSIDE_DOM; + +} + +// This method can be used for call during 'compute_element_modes(): +// --> check 'VertexModus' instead of 'boolian' during is_outside()/is_nearInterface() +template +VertexModus CutElementHandlerBase:: +compute_vertex_modus(Vertex* vrt) +{ + if ( is_nearInterface(vrt) ) + return ON_INTERFACE; + else if ( is_outsideDomain(vrt) ) + return OUTSIDE; + else + return INSIDE; +} + + +template +ElementModus CutElementHandlerBase:: +compute_element_modus(GridObject* elem) +{ + + size_t localInd = -0.5*get_orientation() + 0.5; + + m_vvVertexMode[localInd].clear(); + m_vVertexMode.clear(); + + bool insideDomain = false; + bool outsideDomain = false; + std::vector vVertex; + CollectVertices(vVertex, *m_spMG, elem); + m_aaPos.access(*m_spMG, m_aPos); + + size_t num_onInterface = 0; + size_t num_outside = 0; + size_t num_inside = 0; + +// loop vertices + for(size_t i = 0; i < vVertex.size(); ++i) + { + Vertex* vrt = vVertex[i]; + if ( is_nearInterface(vrt) ) + { + // A. update counter: + num_onInterface++; + + // get_or_insert_vertex_near(m_aaPos[vrt]); // ToDo: brauche ich diese Funktion und daten 'm_MapNearVertices' (in Immersed-Klasse) noch?? + + // B. set local modus + m_vVertexMode.push_back(ON_INTERFACE); + m_vvVertexMode[localInd].push_back(ON_INTERFACE); + + // C. set global modus: BoolMarker + m_spNearInterfaceVrtMarker->mark(vrt); + m_spOutsideMarker->mark(vrt); + + // D. set boolian + outsideDomain = true; + + } + else if ( is_outsideDomain(vrt) ) + { + // A. update counter + num_outside++; + + // B. set local modus + m_vVertexMode.push_back(OUTSIDE); + m_vvVertexMode[localInd].push_back(OUTSIDE); + + // C. set global modus: BoolMarker + m_spOutsideMarker->mark(vrt); + m_spCutMarker->mark(vrt); + + // D. set boolian + outsideDomain = true; + } + else + { + // A. update counter + num_inside++; + + // B. set local modus + m_vVertexMode.push_back(INSIDE); + m_vvVertexMode[localInd].push_back(INSIDE); + + // C. set global modus: BoolMarker + m_spInsideMarker->mark(vrt); + + // D. set boolian + insideDomain = true; + + if ( is_nearInterface(vrt) ) + UG_THROW("CutElementHandlerBase::compute_element_modus(): case 'is_nearInterface(vrt) = true' not possible!\n"); + } + } // vertex loop + + + size_t checkOut = num_onInterface + num_outside; + size_t checkIn = num_onInterface + num_inside; + + if ( checkOut == vVertex.size() ) m_elementModus = OUTSIDE_DOM; + else if ( checkIn == vVertex.size() ) m_elementModus = INSIDE_DOM; + else if (insideDomain && outsideDomain) + { + m_elementModus = CUT_BY_INTERFACE; + m_spCutMarker->mark((grid_base_object*)elem); + } + else if (outsideDomain) + { + m_elementModus = OUTSIDE_DOM; + m_spOutsideMarker->mark((grid_base_object*)elem); + } + else + { + m_elementModus = INSIDE_DOM; + m_spInsideMarker->mark((grid_base_object*)elem); + } + + return m_elementModus; + +} + + +template +void CutElementHandlerBase:: +clear_bool_marker() +{ + m_spNearInterfaceVrtMarker->clear(); + m_spInterfaceVrtMarker->clear(); + m_spOutsideMarker->clear(); + m_spInsideMarker->clear(); + m_spCutMarker->clear(); +} + + +template +void CutElementHandlerBase:: +update_interface_data(ConstSmartPtr dd, const int levIndex) +{ + m_bBoolMarkerInit = true; + +// initialize vectors + m_vvElemList.resize(levIndex + 1); + m_vvElemListCut.resize(levIndex + 1); + m_vvElemListOutside.resize(levIndex + 1); + + m_vvElemList[levIndex].clear(); + m_vvElemListCut[levIndex].clear(); + m_vvElemListOutside[levIndex].clear(); + + +// get data + typedef typename domain_traits::grid_base_object grid_base_object; + + typename DoFDistribution::traits::const_iterator iter, iterEnd; + iter = dd->template begin(); + iterEnd = dd->template end(); + +// loop elements in order to compute the volume and set rhs: + for( ; iter != iterEnd; iter++) + { + // get element + grid_base_object* elem = *iter; + + ElementModus elemModus = compute_element_modus(elem); + + if ( elemModus == CUT_BY_INTERFACE ) + { + m_vvElemList[levIndex].push_back(elem); + m_vvElemListCut[levIndex].push_back(elem); + + // mark vrt in order to remove them from 'm_spOutsideMarker'-list! + for(size_t i = 0; i < elem->num_vertices(); ++i) + { + if ( m_spOutsideMarker->is_marked(elem->vertex(i)) ) + this->m_spInterfaceVrtMarker->mark(elem->vertex(i)); + + // check: all nearInterface-vertices also are outside-vertices: + if ( !m_spOutsideMarker->is_marked(elem->vertex(i)) && + m_spNearInterfaceVrtMarker->is_marked(elem->vertex(i)) ) + UG_THROW("Error: all nearInterface-vertices also are outside-vertices!!\n"); + } + } + else if ( elemModus == OUTSIDE_DOM ) + { + m_vvElemList[levIndex].push_back(elem); + m_vvElemListOutside[levIndex].push_back(elem); + } + else // INSIDE_DOM + { + if ( elemModus != INSIDE_DOM ) + UG_THROW("in 'update_interface_data()': no case found for 'elemModus'!\n"); + } + + } // end elem-loop + + +} + + +} // end ug namespace + +#endif /* CUT_ELEMENT_HANDLER_BASE_IMPL_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/cut_element_handler/cut_element_handler_flat_top_impl.h b/ugbase/lib_disc/spatial_disc/immersed_util/cut_element_handler/cut_element_handler_flat_top_impl.h new file mode 100644 index 000000000..e7fef910b --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/cut_element_handler/cut_element_handler_flat_top_impl.h @@ -0,0 +1,937 @@ +/* + * interface_handler_local_impl.h + * + * Created on: 19.01.2015 + * Author: suze + */ + +#ifndef CUT_ELEMENT_HANDLER_FLAT_TOP_IMPL_H_ +#define CUT_ELEMENT_HANDLER_FLAT_TOP_IMPL_H_ + +#ifdef UG_PARALLEL + #include "pcl/pcl_interface_communicator.h" + #include "lib_grid/refinement/hanging_node_refiner_multi_grid.h" + #include "lib_grid/multi_grid.h" +#endif + +namespace ug{ + +template +CutElementHandler_FlatTop:: +CutElementHandler_FlatTop(SmartPtr mg, const char* fctNames, + SmartPtr > interfaceProvider) + : CutElementHandlerBase(mg, interfaceProvider), + m_fctNames(fctNames), + m_spInterfaceProvider(interfaceProvider) +{ + m_vPrtIndex.resize(3); +} + +template +CutElementHandler_FlatTop:: +CutElementHandler_FlatTop(SmartPtr mg, const char* fctNames, + SmartPtr > interfaceProvider) + : CutElementHandlerBase(mg, interfaceProvider), + m_fctNames(fctNames), + m_spInterfaceProvider(interfaceProvider) +{ + m_vPrtIndex.resize(3); +} + +// checks weather node is transDoF OR rotDoF +template +bool CutElementHandler_FlatTop:: +is_extraDoF(DoFIndex dofIndex, int levIndex) +{ +// pressure dof is always NO extraDoF: + if ( dofIndex[1] == dim ) + return false; + + for (size_t p = 0; p < num_particles(); ++p) + { + +#ifdef UG_PARALLEL + if ( m_vvvElemListCut[levIndex][p].size() == 0 ) { + continue; + } +#endif + // get data + DoFIndex transIndex = get_transInd_Comp(levIndex, p, 0); + DoFIndex rotIndex = get_rotInd_Comp(levIndex, p, 0); + + /// extra index = translational velocity DoF + if ( dofIndex[0] == transIndex[0] ) + { + if ( get_DoF_modus_linear(p) ) + { + return false; + } + else + return true; + } + /// extra index = angular velocity DoF: 2d case => only ONE velocity DoF + else if ( dofIndex[0] == rotIndex[0] ) + { + if ( get_DoF_modus_angular(p) ) + { + return false; + } + else + { + if ( dim == 3 ) return true; + if ( dim == 2 && dofIndex[1] == 0 ) return true; + } + } + } + + return false; +} + +template +MathMatrix CutElementHandler_FlatTop:: +get_rotationMat(MathVector radialVector) +{ + MathMatrix rotationMat; + if ( dim == 2 ) + { + rotationMat[0][0] = -radialVector[1]; + rotationMat[0][1] = 0.0; + + rotationMat[1][0] = radialVector[0]; + rotationMat[1][1] = 0.0; + } + else if ( dim == 3 ) + { + rotationMat[0][0] = 0.0; + rotationMat[0][1] = radialVector[2]; + rotationMat[0][2] = -radialVector[1]; + + rotationMat[1][0] = -radialVector[2]; + rotationMat[1][1] = 0.0; + rotationMat[1][2] = radialVector[0]; + + rotationMat[2][0] = radialVector[1]; + rotationMat[2][1] = -radialVector[0]; + rotationMat[2][2] = 0.0; + } + + return rotationMat; + +} + + +template +bool CutElementHandler_FlatTop:: +is_nearInterface_with_given_index(const int prtIndex, Vertex* vrt) +{ +// get threshold (either default = 1e-10 or set by user via .lua-call: + const number threshold = this->get_threshold(vrt); + +// compute the distance between the location of vrt and the interface: + const number LS_value = get_LSvalue(vrt, prtIndex); + + if (fabs(LS_value) < threshold) + { + set_prtIndex(prtIndex); + return true; + } + + return false; +} + + +template +bool CutElementHandler_FlatTop:: +is_outsideFluid(Vertex* vrt) +{ +// get data + const int orientation = this->get_orientation(); + +// get threshold (either default = 1e-10 or set by user via .lua-call: + const number threshold = this->get_threshold(vrt); + +// loop all particles + for (size_t p = 0; p < m_spInterfaceProvider->num_particles(); ++p) + { + // compute the distance between the location of vrt and the interface: + // level set value: LS_value := radius - distance + const number LS_value = get_LSvalue(vrt, p); + + // compute + if ( LS_value > threshold && orientation == 1 ) + { + set_prtIndex(p); + return true; + } + else if ( LS_value < -threshold && orientation == -1 ) + { + // set particle index to data + set_prtIndex(p); + return true; + } + else if ( is_nearInterface_with_given_index(p, vrt) ) + { + // set particle index to data + set_prtIndex(p); + return true; + } + + } // end particle loop + + return false; +} + +template +bool CutElementHandler_FlatTop:: +is_outsideFluid(int& PrtIndex, Vertex* vrt) +{ + bool outsideFluid = false; + +// get threshold (either default = 1e-10 or set by user via .lua-call: + const number threshold = this->get_threshold(vrt); + +// loop over all centers and pick the index with minimal distance + for (size_t p = 0; p < this->num_particles(); ++p) + { + // compute the distance between the location of vrt and the interface: + // level set value: LS_value := radius - distance + const number LS_value = get_LSvalue(vrt, p); + + if ( LS_value > threshold ) + { + // set particle index to data + PrtIndex = p; + outsideFluid = true; + } + else if ( is_nearInterface_with_given_index(p, vrt) ) + { + // set particle index to data + PrtIndex = p; + outsideFluid = true; + } + } + + return outsideFluid; +} + +template +bool CutElementHandler_FlatTop:: +is_insideParticle_with_given_index(const int prtIndex, Vertex* vrt) +{ + + bool outsideFluid = false; + +// get threshold (either default = 1e-10 or set by user via .lua-call: + const number threshold = this->get_threshold(vrt); + +// compute the distance between the location of vrt and the interface: +// level set value: LS_value := radius - distance + const number LS_value = get_LSvalue(vrt, prtIndex); + + if ( LS_value > threshold ) + { + outsideFluid = true; + } + else if ( is_nearInterface_with_given_index(prtIndex, vrt) ) + { + outsideFluid = true; + } + + return outsideFluid; +} + + +template +void CutElementHandler_FlatTop:: +compute_and_set_prtIndex(GridObject* elem) +{ + m_vPrtIndices.clear(); + +// collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *this->m_spMG, elem); + + std::vector vPrtIndex(vVertex.size(), -1); + int isOutside = 0; + int refIndex = -1; + + // loop all vertices to get prtIndex + for(size_t i = 0; i < vVertex.size(); ++i) + { + if ( is_outsideFluid(vPrtIndex[i], vVertex[i]) ) + { + refIndex = vPrtIndex[i]; + m_vPrtIndices[vVertex[i]] = vPrtIndex[i]; + isOutside++; + } + } + +// SPECIAL case: 1 element is cut by 2 DIFFERENT particles: + bool prtIndexSet = true; + if ( isOutside > 0 ) + { + for(size_t i = 0; i < vVertex.size(); ++i) + { + if ( vPrtIndex[i] != refIndex && vPrtIndex[i] != -1) + { + prtIndexSet = false; + UG_LOG("SPECIAL case: 1 element is cut by 2 DIFFERENT particles! EXIT...\n"); + } + } + } + +// set m_prtIndex to unique prtIndex found: + if ( prtIndexSet ) + set_prtIndex(refIndex); // set_prtIndex() already called during is_outsideFluid()! + +} + + +template +void CutElementHandler_FlatTop:: +update_prtCoords(const int topLevel, const number deltaT) +{ + if ( deltaT == 0.0 ) + UG_THROW("ParticleProvider:update_prtCoords: deltaT = " << deltaT << " => no update necessary!\n"); + +// update center + for (size_t p = 0; p < num_particles(); ++p) + { +#ifdef UG_PARALLEL +// use size of member 'CutElementHandler_FlatTop::m_vvvElemListCut' in order to +// indicate, whether a particle lies on a processor or not + const int levIndex = this->get_Index(GridLevel(topLevel, GridLevel::LEVEL)); + std::vector ElemList = m_vvvElemListCut[levIndex][p]; + UG_LOG("1 CutElementHandler_FlatTop::update_prtCoords() ElemList.size(): " << ElemList.size() << "\n"); + if ( ElemList.size() == 0 ) { + UG_LOG("2 CutElementHandler_FlatTop::update_prtCoords() ElemList.size(): " + << ElemList.size() << " => skip assembling! \n"); + return; + } +#endif + + MathVector transSol = get_transSol(p, 0); + MathVector rotSol = get_rotSol(p, 0); + + // finally update the center of the p-th particle + m_spInterfaceProvider->update(deltaT, transSol, rotSol, p); + + } // end particle loop + +} + + + +template +ElementModus CutElementHandler_FlatTop:: +compute_element_modus(int prtIndex, GridObject* elem) +{ + bool insideFluid = false; + bool outsideFluid = false; + std::vector vVertex; + CollectVertices(vVertex, *this->m_spMG, elem); + this->m_aaPos.access(*this->m_spMG, this->m_aPos); + +// loop vertices + for(size_t i = 0; i < vVertex.size(); ++i) + { + Vertex* vrt = vVertex[i]; + if ( is_nearInterface_with_given_index(prtIndex, vrt) ) + { + outsideFluid = true; + this->m_spNearInterfaceVrtMarker->mark(vrt); + this->m_spOutsideMarker->mark(vrt); + } + else if ( is_insideParticle_with_given_index(prtIndex, vrt) ) + { + outsideFluid = true; + this->m_spOutsideMarker->mark(vrt); + } + else + { + insideFluid = true; + if ( is_nearInterface_with_given_index(prtIndex, vrt) ) + UG_THROW("CutElementHandler_FlatTop::compute_element_modus(): case 'is_nearInterface_with_given_index(vrt) = true' not possible!\n"); + } + + } // vertex loop + + if (insideFluid && outsideFluid) return CUT_BY_INTERFACE; + else if (outsideFluid) return OUTSIDE_DOM; + + return INSIDE_DOM; + +} + + +template +ElementModus CutElementHandler_FlatTop:: +get_element_modus(GridObject* elem) +{ + if ( !this->m_bBoolMarkerInit ) + UG_THROW("global element modus not initialized! Call the method update_interface_data()'\n"); + + if ( this->m_spCutMarker->is_marked(elem) ) + { + return CUT_BY_INTERFACE; + } + else if ( this->m_spOutsideMarker->is_marked(elem) ) + { + return OUTSIDE_DOM; + } + else + return INSIDE_DOM; + +} + + +template +void CutElementHandler_FlatTop:: +update_global_indices(ConstSmartPtr dd, const int levIndex) +{ +// get data + FunctionGroup fctGrp(dd->function_pattern(), TokenizeString(m_fctNames)); + +// initialize vectors + m_vvvGlobalIndices_linearVel.resize(levIndex + 1); + m_vvvGlobalIndices_angularVel.resize(levIndex + 1); + + m_vvvGlobalIndices_linearVel[levIndex].clear(); + m_vvvGlobalIndices_angularVel[levIndex].clear(); + + m_vvvGlobalIndices_linearVel[levIndex].resize(num_particles()); + m_vvvGlobalIndices_angularVel[levIndex].resize(num_particles()); + +// initialize boolian for return value + std::vector ExtraDoFs_found; + for (size_t p = 0; p < this->num_particles(); ++p) + ExtraDoFs_found.push_back(false); + + // initialize distance array + std::vector < number > distance; + distance.clear(); + distance.resize(num_particles(), 10000.0); + typedef typename std::vector::iterator ListIter; + + +/* + * hier keine #ifdef UG_PARALLEL-Abfrage notwendig, da 'm_vvvElemList' leer ist + * auf dem entsprechendem proc => der proc ohne particle ueberspringt schleife sowieso! :) +*/ + + for (size_t p = 0; p < num_particles(); ++p) + { +#ifdef UG_PARALLEL + // use size of member 'CutElementHandler_FlatTop::m_vvvElemListCut' in order to + // indicate, whether a particle lies on a processor or not + std::vector ElemList = m_vvvElemListCut[levIndex][p]; + UG_LOG("1_ update_global_indices() ElemList.size(): " << ElemList.size() << "\n"); + if ( ElemList.size() == 0 ) { + UG_LOG("Process " << pcl::ProcRank() << ": 2_ update_global_indices() ElemList.size(): " + << ElemList.size() << " => skip assembling! \n"); + continue; + } +#endif + + + grid_base_object* transVelElem; + Vertex* transVelVertex; + + // loop all elements covered by the particle in order to pick the DoF-nodes + for (ListIter elemIter = m_vvvElemList[levIndex][p].begin(); + elemIter != m_vvvElemList[levIndex][p].end(); ++elemIter) + { + // get element + grid_base_object* elem = *elemIter; + + // collect vertices + std::vector vVertex; + CollectVertices(vVertex, *this->m_spMG, elem); + + // loop vertices in order to: + // 1) compute sum of distances + // 2) check weather at least two vrt are 'outside_Fluid' + number dist = 0.0; + std::vector vrtArray; + for(size_t i = 0; i < elem->num_vertices(); ++i) + { + // get vertex + Vertex* vrt = elem->vertex(i); + const MathVector& vrtPos = this->m_aaPos[vrt]; + const MathVector& center = get_center(p); + + dist += VecDistance(vrtPos, center); + if (is_insideParticle_with_given_index(p, vrt)) + vrtArray.push_back(vrt); + if (is_insideParticle_with_given_index(p, vrt) && !this->m_spOutsideMarker->is_marked(vrt)) + UG_THROW("Mist, immeroch falsche marker:-(\n"); + } + + // 2) check weather at least two vrt are 'outside_Fluid' + // and pick the node nearest to the center + if (dist < distance[p] && vrtArray.size() >= 2) + { + ExtraDoFs_found[p] = true; + + transVelElem = elem; + transVelVertex = vrtArray[0]; + + distance[p] = dist; + m_vvvGlobalIndices_linearVel[levIndex][p].clear(); + m_vvvGlobalIndices_angularVel[levIndex][p].clear(); + + // create multi index + std::vector < DoFIndex > vInd1; + std::vector < DoFIndex > vInd2; + + // loop all velocity components + for (int d = 0; d < dim; ++d) + { + // get fct id for comopent + const size_t fct = fctGrp[d]; + + // get multi indices + if (dd->inner_dof_indices(vrtArray[0], fct, vInd1) != 1) + UG_THROW("Only one index expected."); + + // get multi indices + if (dd->inner_dof_indices(vrtArray[1], fct, vInd2) != 1) + UG_THROW("Only one index expected."); + + // set multiIndex for ExtraDoFs + m_vvvGlobalIndices_linearVel[levIndex][p].push_back(vInd2[0]); + m_vvvGlobalIndices_angularVel[levIndex][p].push_back(vInd1[0]); + + } // end dim-loop + + } + + + } // end elem-loop + + // security check + if ( !ExtraDoFs_found[p] ) + UG_THROW("ParticleHandlerGlobal:update_global_indices: no ExtraDoFs found for the " + << p << "-th particle!\n"); + + } // end prt-loop + + +} + + +template +void CutElementHandler_FlatTop:: +update_interface_data(ConstSmartPtr dd, const int levIndex) +{ + this->m_bBoolMarkerInit = true; + + // initialize vectors + m_vvvElemList.resize(levIndex + 1); + m_vvvElemListCut.resize(levIndex + 1); + m_vvvElemListOutside.resize(levIndex + 1); + + m_vvvElemList[levIndex].clear(); + m_vvvElemListCut[levIndex].clear(); + m_vvvElemListOutside[levIndex].clear(); + + m_vvvElemList[levIndex].resize(num_particles()); + m_vvvElemListCut[levIndex].resize(num_particles()); + m_vvvElemListOutside[levIndex].resize(num_particles()); + +// get data + typedef typename domain_traits::grid_base_object grid_base_object; + typename DoFDistribution::traits::const_iterator iter, iterEnd; + iter = dd->template begin(); + iterEnd = dd->template end(); + +// loop elements in order to compute the volume and set rhs: + for( ; iter != iterEnd; iter++) + { + // get element + grid_base_object* elem = *iter; + + for (size_t prtIndex = 0; prtIndex < num_particles(); ++prtIndex) + { + ElementModus elemModus = compute_element_modus(prtIndex, elem); + + if ( elemModus == CUT_BY_INTERFACE ) + { + m_vvvElemList[levIndex][prtIndex].push_back(elem); + m_vvvElemListCut[levIndex][prtIndex].push_back(elem); + + this->m_spCutMarker->mark(elem); + + // for dim = 3: exclude Pyramids from assembling, i.e. set outside nodes to 'near_interface', so that element lies inside: + bool isPyramid = false; + if ( dim == 3 ) + { + if ( element_is_pyramid(elem) ) + { + isPyramid = true; + UG_LOG("isPyramid = true...\n"); + } + } + + // mark vrt in order to remove them from 'm_spOutsideMarker'-list! + for(size_t i = 0; i < elem->num_vertices(); ++i) + { + if ( is_insideParticle_with_given_index(prtIndex, elem->vertex(i)) ) + { + this->m_spCutMarker->mark(elem->vertex(i)); + this->m_spInterfaceVrtMarker->mark(elem->vertex(i)); + + // for pyramids, set ALL outside nodes to 'nearInterface' nodes + // => in 'get_cutMode()': numOutside == numNearInterface => original tetrahedron + if ( isPyramid ) + { + this->m_spNearInterfaceVrtMarker->mark(elem->vertex(i)); + } + else if ( is_nearInterface_with_given_index(prtIndex, elem->vertex(i))) + { + if ( !this->m_spNearInterfaceVrtMarker->is_marked(elem->vertex(i))) + UG_THROW("hmmm...muesste schon laengst markiert sein...oder noch nicht implementiert in 'is_nearInterface!!\n"); + } + } + } + } + else if ( elemModus == OUTSIDE_DOM ) + { + this->m_spOutsideMarker->mark(elem); + m_vvvElemList[levIndex][prtIndex].push_back(elem); + m_vvvElemListOutside[levIndex][prtIndex].push_back(elem); + } + else // INSIDE_DOM + { + if ( elemModus != INSIDE_DOM ) + UG_THROW("in 'update_interface_data()': no case found for 'elemModus'!\n"); + } + + } // end particle loop + } // end elem-loop + +} + + + +// same fuction as in class 'FlatTopHandler', but since m_spParticleHandlerLocal is not a member of +// CutElementHandler_FlatTop, there is no option for using it +template +bool CutElementHandler_FlatTop:: +element_is_pyramid(grid_base_object* elem) +{ + + size_t numOutside = 0; + size_t numNearInterface = 0; + + for(size_t i = 0; i < elem->num_vertices(); ++i) + { + if ( is_outsideFluid(elem->vertex(i)) ) + { + numOutside++; + if ( is_nearInterfaceVertex(elem->vertex(i), i) ) + numNearInterface++; + } + } + +// Pyramid + if ( numOutside == 2 && numNearInterface == 1 ) + return true; + + return false; + +} + + + +template +void CutElementHandler_FlatTop:: +update_multigrid_data(ConstSmartPtr dd, const int levIndex) +{ +// 1. 'update_interface_data()': +// --> all BoolMarker and the element lists are written + update_interface_data(dd, levIndex); + +// 2. set 'm_vvvGlobalIndices_linearVel/m_vvvGlobalIndices_angularVel' + update_global_indices(dd, levIndex); + +} + + +template +void CutElementHandler_FlatTop:: +print_elem_lists(ConstSmartPtr dd) +{ + +// get data + typedef typename DoFDistribution::traits::const_iterator ElemIter; + ElemIter iterBegin = dd->begin(); + ElemIter iterEnd = dd->end(); + + const char* filename; + std::string name; + char ext[50]; sprintf(ext, "txt"); + FILE* printFile; + + // loop elements in order to compute the volume and set rhs: + for(ElemIter elemIter = iterBegin; elemIter != iterEnd; ++elemIter) + { + // get element + grid_base_object* elem = *elemIter; + + // get all corner coordinates + std::vector > vCornerCoords; + CollectCornerCoordinates(vCornerCoords, *elem, this->m_aaPos); + + if ( this->m_spOutsideMarker->is_marked(elem) ) + { + filename = "File_OutsideMarker."; + name = filename; + name.append(ext); + printFile = fopen(name.c_str(), "a"); + fprintf(printFile, "------------------------------------------------------\n\n new triangle: \n"); + for ( size_t i = 0; i < 3; ++i ) + fprintf(printFile," vCornerCoords: %e, %e \n", vCornerCoords[i][0], vCornerCoords[i][1]); + fclose(printFile); + } + if ( this->m_spInterfaceVrtMarker->is_marked(elem) ) + { + filename = "File_TrueCutElemMarker."; + name = filename; + name.append(ext); + printFile = fopen(name.c_str(), "a"); + fprintf(printFile, "------------------------------------------------------\n\n new triangle: \n"); + for ( size_t i = 0; i < 3; ++i ) + fprintf(printFile," vCornerCoords: %e, %e \n", vCornerCoords[i][0], vCornerCoords[i][1]); + fclose(printFile); + } + + + // loop vertices + for(size_t i = 0; i < elem->num_vertices(); ++i) + { + // get vertex + Vertex* vrt = elem->vertex(i); + if ( this->m_spInterfaceVrtMarker->is_marked(vrt) ) + { + filename = "File_m_pFlatTopMarker_Vrt."; + name = filename; + name.append(ext); + printFile = fopen(name.c_str(), "a"); + fprintf(printFile," vCornerCoords: %e, %e \n", this->m_aaPos[vrt][0], this->m_aaPos[vrt][1]); + fclose(printFile); + } + if ( this->m_spOutsideMarker->is_marked(vrt) ) + { + filename = "File_m_pOutsideMarker_Vrt."; + name = filename; + name.append(ext); + printFile = fopen(name.c_str(), "a"); + fprintf(printFile," vCornerCoords: %e, %e \n", this->m_aaPos[vrt][0], this->m_aaPos[vrt][1]); + fclose(printFile); + } + if ( !this->m_spOutsideMarker->is_marked(vrt) && !this->m_spInterfaceVrtMarker->is_marked(vrt) ) + { + filename = "File_m_pInsideMarker_Vrt."; + name = filename; + name.append(ext); + printFile = fopen(name.c_str(), "a"); + fprintf(printFile," vCornerCoords: %e, %e \n", this->m_aaPos[vrt][0], this->m_aaPos[vrt][1]); + fclose(printFile); + } + if ( this->m_spNearInterfaceVrtMarker->is_marked(vrt) ) + { + filename = "File_m_pNearInterfaceVrtMarker_Vrt."; + name = filename; + name.append(ext); + printFile = fopen(name.c_str(), "a"); + fprintf(printFile," vCornerCoords: %e, %e \n", this->m_aaPos[vrt][0], this->m_aaPos[vrt][1]); + fclose(printFile); + } + + } + } + + +} + + +#ifdef UG_PARALLEL +template +void CutElementHandler_FlatTop:: +synchronize_particles(int levIndex) { + + bool verbose = false; + +#ifdef UG_DEBUG + verbose = true; +#endif + + pcl::ProcessCommunicator com; + + if (active_mpi_routine == 1) { + /////////////////////////////////////// + // Synchronisation using Allreduce // + /////////////////////////////////////// + for (size_t p = 0; p < num_particles(); ++p) + { + if (verbose) { + UG_LOG("Synchronize particle " << p << ".\n"); + UG_LOG("m_vvvElemListCut.size(): " << m_vvvElemListCut.size() << ".\n"); + UG_LOG("m_vvvElemListCut[levIndex].size(): " << m_vvvElemListCut[levIndex].size() << ".\n"); + UG_LOG("m_vvvElemListCut[levIndex][" << p << "].size(): " << m_vvvElemListCut[levIndex][p].size() << ".\n"); + } + std::vector ElemList = m_vvvElemListCut[levIndex][p]; + if (verbose) + UG_LOG("Process " << pcl::ProcRank() << ": 1_ synchronize_particles() ElemList.size(): " << ElemList.size() << "\n"); + if ( ElemList.size() == 0 ) { + // send zero vector as center to all other processes + std::vector zero_values(3*dim,0.0); + std::vector values(3*dim,0.0); + com.allreduce(&zero_values[0], &values[0], 3*dim, MPI_DOUBLE, PCL_RO_SUM); + MathVector center; + MathVector linearVelocity; + MathVector angularVelocity; + for (size_t i = 0; i < dim; ++i) { + center[i] = values[i]; + linearVelocity[i] = values[dim+i]; + angularVelocity[i] = values[2*dim+i]; + } + if (verbose) { + UG_LOG("Process " << pcl::ProcRank() << ": setting center to " << center << "\n"); + UG_LOG("Process " << pcl::ProcRank() << ": setting linear velocity to " << linearVelocity << "\n"); + UG_LOG("Process " << pcl::ProcRank() << ": setting angular velocity to " << angularVelocity << ")\n"); + } + m_spInterfaceProvider->set_center(center, p); + m_spInterfaceProvider->set_linear_velocity(linearVelocity, p, 0); + m_spInterfaceProvider->set_angular_velocity(angularVelocity, p, 0); + } else { + // send correct center value to all other processes. Since all other processes should send zeros the allreduce with PCL_RO_SUM results in the correct center values on all processes. + MathVector center = m_spInterfaceProvider->get_center(p); + MathVector linearVelocity = m_spInterfaceProvider->get_linear_velocity(p, 0); + MathVector angularVelocity = m_spInterfaceProvider->get_angular_velocity(p, 0); + std::vector values(3*dim,0.0); + for (size_t i = 0; i < dim; ++i) { + values[i] = center[i]; + values[dim+i] = linearVelocity[i]; + values[2*dim+i] = angularVelocity[i]; + } + MathVector<3*dim> new_values; + com.allreduce(&values[0], &new_values[0], 3*dim, MPI_DOUBLE, PCL_RO_SUM); + MathVector new_center; + MathVector new_linearVelocity; + MathVector new_angularVelocity; + + for (size_t i = 0; i < dim; ++i) { + new_center[i] = new_values[i]; + new_linearVelocity[i] = new_values[dim+i]; + new_angularVelocity[i] = new_values[2*dim+i]; + } + if (verbose) + UG_LOG("Process " << pcl::ProcRank() << ": setting center to " << new_center << "\n"); + m_spInterfaceProvider->set_center(new_center, p); + if (verbose) + UG_LOG("Process " << pcl::ProcRank() << ": setting linear velocity to " << new_linearVelocity << "\n"); + m_spInterfaceProvider->set_linear_velocity(new_linearVelocity, p, 0); + if (verbose) + UG_LOG("Process " << pcl::ProcRank() << ": setting angular velocity to " << new_angularVelocity << "\n"); + m_spInterfaceProvider->set_angular_velocity(new_angularVelocity, p, 0); + } + } + } else { + + //////////////////////////////////////// + // Synchronisation using Interfaces // + //////////////////////////////////////// + // Create up to date particle data struct + if (verbose) + UG_LOG("Create data struct.\n"); + CombinedParticleData particleValues; + ParticleData dataSet; + for (size_t p = 0; p < num_particles(); ++p) { + std::vector ElemList = m_vvvElemListCut[levIndex][p]; + if ( ElemList.size() == 0 ) { + MathVector center; + if (verbose) + UG_LOG(pcl::ProcRank() << " sends zeros.\n"); + for (std::size_t i = 0; i < dim; ++i){ + center[i] = 0.0; + dataSet.transVel[i] = 0.0; + dataSet.rotVel[i] = 0.0; + } + dataSet.center = center; + dataSet.valid = false; + } else { + dataSet.center = m_spInterfaceProvider->get_center(p); + dataSet.transVel = m_spInterfaceProvider->get_linear_velocity(p, 0); + dataSet.rotVel = m_spInterfaceProvider->get_angular_velocity(p, 0); + dataSet.valid = true; + if (verbose) { + UG_LOG(pcl::ProcRank() << " sends\n" ); + UG_LOG("(" << dataSet.center[0] << ", " << dataSet.center[1] << ")\n"); + UG_LOG("(" << dataSet.transVel[0] << ", " << dataSet.transVel[1] << ")\n"); + UG_LOG("(" << dataSet.rotVel[0] << ", " << dataSet.rotVel[1] << ")\n"); + UG_LOG(std::boolalpha << dataSet.valid); + } + } + particleValues.push_back(dataSet); + } + if (verbose) + UG_LOG("Struct created.\n"); + com.barrier(); + + ParticleData default_new_data; + MathVector zero_vec; + for (std::size_t i = 0; i < dim; ++i){ + zero_vec[i] = 0.0; + } + default_new_data.valid = false; + default_new_data.center = zero_vec; + default_new_data.transVel = zero_vec; + default_new_data.rotVel = zero_vec; + CombinedParticleData new_particleData(num_particles(),default_new_data); + + const GridLayoutMap& glm = this->m_spMG->distributed_grid_manager()->grid_layout_map(); + for (std::size_t proc = 0; proc < pcl::NumProcs(); ++proc) { + if (verbose) + UG_LOG("proc " << proc << " sends to "); + if (glm.has_layout(INT_H_MASTER)) + { + const typename GridLayoutMap::Types::Layout& vrt_hm_layout = glm.get_layout(INT_H_MASTER); + if (vrt_hm_layout.interface_exists(proc, levIndex)) + { + for (GridLayoutMap::Types::Layout::const_iterator it = vrt_hm_layout.begin(levIndex); it != vrt_hm_layout.begin(levIndex); ++it) { + com.send_data(&particleValues, sizeof(particleValues), vrt_hm_layout.proc_id(it), proc); + //UG_LOG(vrt_hm_layout.proc_id(it) << " "); + } + } + } + if (glm.has_layout(INT_H_SLAVE)) + { + const typename GridLayoutMap::Types::Layout& vrt_hm_layout = glm.get_layout(INT_H_SLAVE); + if (vrt_hm_layout.interface_exists(proc, levIndex)) + { + for (GridLayoutMap::Types::Layout::const_iterator it = vrt_hm_layout.begin(levIndex); it != vrt_hm_layout.begin(levIndex); ++it) { + com.receive_data(&new_particleData, sizeof(new_particleData), vrt_hm_layout.proc_id(it), proc); + } + } + } + } + if (verbose) + UG_LOG("\n") + for (size_t p = 0; p < num_particles(); ++p) { + if (new_particleData[p].valid) { + m_spInterfaceProvider->set_center(new_particleData[p].center, p); + m_spInterfaceProvider->set_linear_velocity(new_particleData[p].transVel, p, 0); + m_spInterfaceProvider->set_angular_velocity(new_particleData[p].rotVel, p, 0); + } + } + } + } +#endif + +} // end ug namespace + + + +#endif /* CUT_ELEMENT_HANDLER_FLAT_TOP_IMPL_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/cut_element_handler/cut_element_handler_two_sided_impl.h b/ugbase/lib_disc/spatial_disc/immersed_util/cut_element_handler/cut_element_handler_two_sided_impl.h new file mode 100644 index 000000000..6bc8063fe --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/cut_element_handler/cut_element_handler_two_sided_impl.h @@ -0,0 +1,199 @@ +/* + * interface_handler_local_impl.h + * + * Created on: 19.01.2015 + * Author: suze + */ + +#ifndef CUT_ELEMENT_HANDLER_TWO_SIDED_IMPL_H_ +#define CUT_ELEMENT_HANDLER_TWO_SIDED_IMPL_H_ + + + +namespace ug{ + + +template +CutElementHandler_TwoSided:: +CutElementHandler_TwoSided(SmartPtr mg, const char* fctNames, + SmartPtr > interfaceProvider) + : CutElementHandlerBase(mg, interfaceProvider), + m_spInterfaceProvider(interfaceProvider), + m_bElementNearInterface(false) +{ + m_vPrtIndex.resize(3); + + m_verticesNearPos.clear(); + m_MapNearVertices.clear(); + +} + + +template +bool CutElementHandler_TwoSided:: +is_nearInterface(Vertex* vrt) +{ +// get threshold (either default = 1e-10 or set by user via .lua-call: + const number threshold = this->get_threshold(vrt); + +// loop all particles: + for (size_t p = 0; p < m_spInterfaceProvider->num_particles(); ++p) + { + // compute the distance between the location of vrt and the interface: + // level set value: LS_value := radius - distance + const number LS_value = get_LSvalue(vrt, p); + + if (fabs(LS_value) < threshold) + { + set_prtIndex(p); + return true; + } + + } // end particle loop + + return false; +} + + +template +bool CutElementHandler_TwoSided:: +is_outsideDomain(Vertex* vrt) +{ +// get data + const int orientation = this->get_orientation(); + +// get threshold (either default = 1e-10 or set by user via .lua-call: + const number threshold = this->get_threshold(vrt); + + // loop all particles + for (size_t p = 0; p < m_spInterfaceProvider->num_particles(); ++p) + { + // compute the distance between the location of vrt and the interface: + // level set value: LS_value := radius - distance + const number LS_value = get_LSvalue(vrt, p); + + // compute + if ( LS_value > threshold && orientation == 1 ) + { + set_prtIndex(p); + return true; + } + else if ( LS_value < -threshold && orientation == -1 ) + { + set_prtIndex(p); + return true; + } + else if ( is_nearInterface(vrt) ) + { + set_prtIndex(p); + return true; + } + + } // end particle loop + + return false; +} + +template +bool CutElementHandler_TwoSided:: +is_outsideDomain(int& PrtIndex, Vertex* vrt) +{ + bool outsideFluid = false; + +// get threshold (either default = 1e-10 or set by user via .lua-call: + const number threshold = this->get_threshold(vrt); + +// loop over all centers and pick the index with minimal distance + for (size_t p = 0; p < this->num_particles(); ++p) + { + // compute the distance between the location of vrt and the interface: + // level set value: LS_value := radius - distance + const number LS_value = get_LSvalue(vrt, p); + + if ( LS_value > threshold ) + { + PrtIndex = p; + outsideFluid = true; + } + else if ( is_nearInterface(vrt) ) + { + PrtIndex = p; + outsideFluid = true; + } + } + + return outsideFluid; +} + +template +void CutElementHandler_TwoSided:: +compute_and_set_prtIndex(GridObject* elem) +{ + m_vPrtIndices.clear(); + +// collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *this->m_spMG, elem); + + std::vector vPrtIndex(vVertex.size(), -1); + int isOutside = 0; + int refIndex = -1; + +// loop all vertices to get prtIndex + for(size_t i = 0; i < vVertex.size(); ++i) + { + if ( is_outsideDomain(vPrtIndex[i], vVertex[i]) ) + { + refIndex = vPrtIndex[i]; + m_vPrtIndices[vVertex[i]] = vPrtIndex[i]; + isOutside++; + } + } + +// SPECIAL case: 1 element is cut by 2 DIFFERENT particles: + bool prtIndexSet = true; + if ( isOutside > 0 ) + { + for(size_t i = 0; i < vVertex.size(); ++i) + { + if ( vPrtIndex[i] != refIndex && vPrtIndex[i] != -1) + { + prtIndexSet = false; + UG_LOG("SPECIAL case: 1 element is cut by 2 DIFFERENT particles! EXIT...\n"); + } + } + } + +// set m_prtIndex to unique prtIndex found: + if ( prtIndexSet ) + set_prtIndex(refIndex); // set_prtIndex() already called during is_outsideFluid()! +} + + + +template +size_t CutElementHandler_TwoSided:: +get_or_insert_vertex_near(const MathVector& vrtPos) +{ + std::pair,size_t>::iterator,bool> ret; + ret = m_MapNearVertices.insert ( std::pair,size_t>(vrtPos,m_MapNearVertices.size()) ); + + if (ret.second==false) { + //UG_LOG("element already existed with a value of " << ret.first->second << "\n"); + } + else{ + m_verticesNearPos.push_back(vrtPos); + } + + + return ret.first->second; +} + + + + +} // end ug namespace + + + +#endif /* CUT_ELEMENT_HANDLER_TWO_SIDED_IMPL_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/gmg_transfer/Info File b/ugbase/lib_disc/spatial_disc/immersed_util/gmg_transfer/Info File new file mode 100644 index 000000000..92565483a --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/gmg_transfer/Info File @@ -0,0 +1,11 @@ +/* Info File for 'ParticleTransfer' class: */ + +The 'ParticleTransfer' class imlements adapted interpolation operators for the application on cut elements due to immersed interfaces. It mainly performs a re-definition of the local weights due to the new geometry (which is in particular the edge lenght) of the cut element. + +A detailed description of the re-definition of the weights can be found in [1]. + + + +[1] S. Höllbacher. + 'Voll gekoppelte Modellierung zur direkten numerischen Simulation partikulärer Fluide.' + PhD thesis, Universitat Frankfurt, 2016. diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/gmg_transfer/particle_transfer.h b/ugbase/lib_disc/spatial_disc/immersed_util/gmg_transfer/particle_transfer.h new file mode 100644 index 000000000..1929a5445 --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/gmg_transfer/particle_transfer.h @@ -0,0 +1,302 @@ +/* + * Copyright (c) 2010-2015: G-CSC, Goethe University Frankfurt + * Author: Susanne Hoellbacher + * + * This file is part of UG4. + * + * UG4 is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License version 3 (as published by the + * Free Software Foundation) with the following additional attribution + * requirements (according to LGPL/GPL v3 §7): + * + * (1) The following notice must be displayed in the Appropriate Legal Notices + * of covered and combined works: "Based on UG4 (www.ug4.org/license)". + * + * (2) The following notice must be displayed at a prominent place in the + * terminal output of covered works: "Based on UG4 (www.ug4.org/license)". + * + * (3) The following bibliography is recommended for citation and must be + * preserved in all covered files: + * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively + * parallel geometric multigrid solver on hierarchically distributed grids. + * Computing and visualization in science 16, 4 (2013), 151-164" + * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel + * flexible software system for simulating pde based models on high performance + * computers. Computing and visualization in science 16, 4 (2013), 165-179" + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +#ifndef __H__UG__LIB_DISC__OPERATOR__LINEAR_OPERATOR__PARTICLE_TRANSFER__ +#define __H__UG__LIB_DISC__OPERATOR__LINEAR_OPERATOR__PARTICLE_TRANSFER__ + +// extern headers +#include + +// other ug4 modules +#include "common/common.h" +#include "lib_disc/operator/linear_operator/transfer_interface.h" +#include "lib_algebra/operator/debug_writer.h" +#include "../cut_element_handler/cut_element_handler.h" + +#ifdef UG_PARALLEL +#include "lib_disc/parallelization/parallelization_util.h" +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Almost the same implementation as 'StdTransfer' (see std_transfer.h) +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// Changes compared to the StdTransfer class are the call of +// 'modify_vector()' in the method 'prolongate()' and 'restrict()'. +// +// The physical solution values are set in each inactive nodes within +// particles in order to transfer the valid solutions between the levels. +//////////////////////////////////////////////////////////////////////////////// + +namespace ug{ + +//template +//class Particle; + +/// Prologation Operator for P1 Approximation Spaces + +template +class ParticleTransfer : + virtual public ITransferOperator +{ + public: + /// world Dimension + static const int dim = TDomain::dim; + + /// Type of base class + typedef ITransferOperator base_type; + + /// Type of Algebra + typedef TAlgebra algebra_type; + + /// Type of Vector + typedef typename TAlgebra::vector_type vector_type; + + /// Type of Matrix + typedef typename TAlgebra::matrix_type matrix_type; + + /// Type of Domain + typedef TDomain domain_type; + + /// Type of GridFunction + typedef GridFunction GF; + + typedef typename domain_traits::grid_base_object grid_base_object; + + public: + /// Constructor + ParticleTransfer(SmartPtr > approxSpace, SmartPtr > cutElementHandler) : + ITransferOperator(), + m_p1LagrangeOptimizationEnabled(true), + m_dampRes(1.0), bCached(true), m_bUseTransposed(false), + m_spDebugWriter(NULL), + m_spCutElementHandler(cutElementHandler) + {}; + + /// Default constructor + ParticleTransfer() : ITransferOperator(), + m_p1LagrangeOptimizationEnabled(true), + m_dampRes(1.0), m_dampProl(1.0), + bCached(true), m_bUseTransposed(false), + m_spDebugWriter(NULL) + {}; + + /// virtual destructor + virtual ~ParticleTransfer(){}; + + /// set restriction damping (only applied on vector operation, not (!!) in assembled matrices) + void set_restriction_damping(number damp) {m_dampRes = damp;} + + /// set prolongation damping (only applied on vector operation, not (!!) in assembled matrices) + void set_prolongation_damping(number damp) {m_dampProl = damp;} + + /// set debug writer + void set_debug(SmartPtr > spDebugWriter) { + m_spDebugWriter = spDebugWriter; + } + /// computes the mode for setting the weighting alpha for the edges during prolongate_p1(): + size_t get_vertex_mode(Vertex* coarseVrt0, Vertex* coarseVrt1, Vertex* childVrt ); + size_t get_vertex_index(Vertex* vrt, GridObject* elem); + + /// enables/disables an assembling optimization for p1-lagrange elements + /** The optimization is enabled by default. It can however only be used, + * if all elements are refined with their standard refinement rule. If one + * uses anisotropic refinement or refinement with closure, the optimization + * should be disabled. + * \todo The normal assembling strategy should be optimized in such a way + * that the p1-lagrange optimization is no longer required. This + * however involves something like a ref-type-hash for each element, + * which returns a unique number based on the types and order of children.*/ + void enable_p1_lagrange_optimization(bool enable) {m_p1LagrangeOptimizationEnabled = enable;} + bool p1_lagrange_optimization_enabled() const {return m_p1LagrangeOptimizationEnabled;} + + /// sets if restriction and prolongation are transposed + void set_use_transposed(bool bTransposed) {m_bUseTransposed = bTransposed;} + /// sets if restriction and prolongation are transposed + void set_global_handler(SmartPtr > spCutElementHandler) {m_spCutElementHandler = spCutElementHandler;} + + + public: + /// Set levels + virtual void set_levels(GridLevel coarseLevel, GridLevel fineLevel) {} + + /// initialize the operator + virtual void init() {} + + /// returns new instance with same setting + virtual SmartPtr > clone(); + + /// apply Operator, interpolate function + virtual void prolongate(vector_type& uFine, const vector_type& uCoarse){ + GF* pFine = dynamic_cast(&uFine); + const GF* pCoarse = dynamic_cast(&uCoarse); + if(!pFine || !pCoarse) + UG_THROW("ParticleTransfer: fine and coarse vectors expected to be " + "a grid function."); + prolongate(*pFine, *pCoarse); + } + + /// necessary adjustment for transInd and rotInd: + void adjust_prolongation(vector_type& corrFine, GridLevel fineLvl, + const vector_type& corrCoarse, GridLevel coarseLvl, + ConstSmartPtr > spApproxSpace); + + /// apply transposed Operator, restrict function + virtual void do_restrict(vector_type& uCoarse, const vector_type& uFine){ + const GF* pFine = dynamic_cast(&uFine); + GF* pCoarse = dynamic_cast(&uCoarse); + if(!pFine || !pCoarse) + UG_THROW("ParticleTransfer: fine and coarse vectors expected to be " + "a grid function."); + do_restrict(*pCoarse, *pFine); + } + + /// necessary adjustment for transInd and rotInd: + void adjust_restriction(vector_type& dCoarse, GridLevel coarseLvl, + const vector_type& dFine, GridLevel fineLvl, + ConstSmartPtr > spApproxSpace); + + /// helper function called during adjust_prolongation()/adjust_restriction(): + void set_solution_to_zero(vector_type& sol, const int levIndex, const int prtIndex, ConstSmartPtr dd); + + + public: + /// returns prolongation as a matrix + virtual SmartPtr + prolongation(const GridLevel& fineGL, const GridLevel& coarseGL, + ConstSmartPtr > spApproxSpace); + + /// returns restriction as a matrix + virtual SmartPtr + restriction(const GridLevel& coarseGL, const GridLevel& fineGL, + ConstSmartPtr > spApproxSpace); + + /// apply operator to a grid function + void prolongate(GF& uFine, const GF& uCoarse); + + /// apply operator to a grid function + void do_restrict(GF& uCoarse, const GF& uFine); + + protected: + /// debug writing of matrix + void write_debug(const matrix_type& mat, std::string name, + const GridLevel& glTo, const GridLevel& glFrom); + + template + void assemble_restriction(matrix_type& mat, + const DoFDistribution& coarseDD, + const DoFDistribution& fineDD, + ConstSmartPtr spDomain); + void assemble_restriction(matrix_type& mat, + const DoFDistribution& coarseDD, + const DoFDistribution& fineDD, + ConstSmartPtr spDomain); + + template + void assemble_prolongation(matrix_type& mat, + const DoFDistribution& fineDD, + const DoFDistribution& coarseDD, + ConstSmartPtr spDomain); + void assemble_prolongation(matrix_type& mat, + const DoFDistribution& fineDD, + const DoFDistribution& coarseDD, + ConstSmartPtr spDomain); + + void assemble_prolongation_p1(matrix_type& mat, + const DoFDistribution& fineDD, + const DoFDistribution& coarseDD); + + protected: + /// struct to distinguish already assembled operators + struct TransferKey{ + TransferKey(const GridLevel& toGL_, const GridLevel& fromGL_, + const RevisionCounter& revCnt_) + : toGL(toGL_), fromGL(fromGL_), revCnt(revCnt_) {} + GridLevel toGL, fromGL; + RevisionCounter revCnt; + + bool operator<(const TransferKey& other) const { + if(revCnt != other.revCnt) return revCnt < other.revCnt; + if(toGL != other.toGL) return toGL < other.toGL; + return fromGL < other.fromGL; + } + }; + + typedef std::map > TransferMap; + TransferMap m_mRestriction; + TransferMap m_mProlongation; + + void remove_outdated(TransferMap& map, const RevisionCounter& revCnt) { + typedef typename TransferMap::iterator iterator; + for(iterator iter = map.begin(); iter != map.end();) + { + const RevisionCounter& cnt = iter->first.revCnt; + if((cnt.obj() == revCnt.obj()) && (cnt != revCnt)){ + map.erase(iter++); + } else { + ++iter; + } + } + } + + protected: + /// list of post processes + using base_type::m_vConstraint; + + /// flag for p1-lagrange-optimization + bool m_p1LagrangeOptimizationEnabled; + + /// damping parameter + number m_dampRes; + number m_dampProl; + + /// flag if cached (matrix) transfer used + bool bCached; + + /// flag if transposed is used + bool m_bUseTransposed; + + /// debug writer + SmartPtr > m_spDebugWriter; + + // new member + SmartPtr > m_spCutElementHandler; + + +}; + +} // end namespace ug + +#include "particle_transfer_impl.h" + +#endif /* __H__UG__LIB_DISC__OPERATOR__LINEAR_OPERATOR__PARTICLE_TRANSFER__ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/gmg_transfer/particle_transfer_impl.h b/ugbase/lib_disc/spatial_disc/immersed_util/gmg_transfer/particle_transfer_impl.h new file mode 100644 index 000000000..71d5d7f77 --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/gmg_transfer/particle_transfer_impl.h @@ -0,0 +1,1483 @@ +/* + * Copyright (c) 2012-2015: G-CSC, Goethe University Frankfurt + * Author: Susanne Hoellbacher + * + * This file is part of UG4. + * + * UG4 is free software: you can redistribute it and/or modify it under the + * terms of the GNU Lesser General Public License version 3 (as published by the + * Free Software Foundation) with the following additional attribution + * requirements (according to LGPL/GPL v3 §7): + * + * (1) The following notice must be displayed in the Appropriate Legal Notices + * of covered and combined works: "Based on UG4 (www.ug4.org/license)". + * + * (2) The following notice must be displayed at a prominent place in the + * terminal output of covered works: "Based on UG4 (www.ug4.org/license)". + * + * (3) The following bibliography is recommended for citation and must be + * preserved in all covered files: + * "Reiter, S., Vogel, A., Heppner, I., Rupp, M., and Wittum, G. A massively + * parallel geometric multigrid solver on hierarchically distributed grids. + * Computing and visualization in science 16, 4 (2013), 151-164" + * "Vogel, A., Reiter, S., Rupp, M., Nägel, A., and Wittum, G. UG4 -- a novel + * flexible software system for simulating pde based models on high performance + * computers. Computing and visualization in science 16, 4 (2013), 165-179" + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + */ + +#ifndef __H__UG__LIB_DISC__OPERATOR__LINEAR_OPERATOR__PARTICLE_TRANSFER_IMPL__ +#define __H__UG__LIB_DISC__OPERATOR__LINEAR_OPERATOR__PARTICLE_TRANSFER_IMPL__ + +#include "particle_transfer.h" +#include "lib_disc/reference_element/reference_mapping_provider.h" +#include "lib_disc/local_finite_element/local_finite_element_provider.h" +#include "lib_disc/function_spaces/grid_function_util.h" +#include "lib_grid/algorithms/debug_util.h" // ElementDebugInfo + +//////////////////////////////////////////////////////////////////////////////// +// Almost the same implementation as 'ParticleTransfer' (see std_transfer.h) +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +// Changes compared to the 'ParticleTransfer' class are the call of +// 'modify_vector()' in the method 'prolongate()' and 'restrict()'. +// +// The physical solution values are set in each inactive nodes within +// particles in order to transfer the valid solutions between the levels. +//////////////////////////////////////////////////////////////////////////////// + + +namespace ug{ + + template + void ParticleAssembleInjectionForP1Lagrange1(typename TAlgebra::matrix_type& mat, + const DoFDistribution& coarseDD, + const DoFDistribution& fineDD) + { + + PROFILE_FUNC_GROUP("gmg"); + // Allow only lagrange P1 functions + for(size_t fct = 0; fct < fineDD.num_fct(); ++fct) + if(fineDD.local_finite_element_id(fct).type() != LFEID::LAGRANGE || + fineDD.local_finite_element_id(fct).order() != 1) + UG_THROW("AssembleInjectionForP1Lagrange: " + "Interpolation only implemented for Lagrange P1 functions."); + + // get MultiGrid + const MultiGrid& grid = *coarseDD.multi_grid(); + + // get number of dofs on different levels + // const size_t numFineDoFs = fineDD.num_indices(); + // const size_t numCoarseDoFs = coarseDD.num_indices(); + + // resize matrix + //mat.resize_and_clear(numCoarseDoFs, numFineDoFs); + + std::vector coarseInd, fineInd; + + // RegularVertex iterators + typedef DoFDistribution::traits::const_iterator const_iterator; + const_iterator iter, iterBegin, iterEnd; + + iterBegin = fineDD.template begin(); + iterEnd = fineDD.template end(); + + // loop nodes of fine subset + for(iter = iterBegin; iter != iterEnd; ++iter) + { + // get father + GridObject* geomObj = grid.get_parent(*iter); + Vertex* vert = dynamic_cast(geomObj); + + // Check if father is RegularVertex + if(vert != NULL) + { + // get global indices + coarseDD.inner_algebra_indices(vert, coarseInd); + } + else continue; + + // get global indices + fineDD.inner_algebra_indices(*iter, fineInd); + + for(size_t i = 0; i < coarseInd.size(); ++i) + mat(coarseInd[i], fineInd[i]) = 1.0; + } + } + + + template + void ParticleAssembleInjectionForP1Lagrange2(typename TAlgebra::matrix_type& P, + const DoFDistribution& coarseDD, + const DoFDistribution& fineDD) + { + UG_THROW("OK2...\n"); + PROFILE_FUNC_GROUP("gmg"); + // allow only lagrange P1 functions + for(size_t fct = 0; fct < fineDD.num_fct(); ++fct) + if(fineDD.lfeid(fct).type() != LFEID::LAGRANGE || + fineDD.lfeid(fct).order() != 1) + UG_THROW("AssembleStdProlongationForP1Lagrange:" + "Interpolation only implemented for Lagrange P1 functions."); + + // resize matrix + P.resize_and_clear(fineDD.num_indices(), coarseDD.num_indices()); + + // iterators + const MultiGrid& mg = *coarseDD.multi_grid(); + typedef DoFDistribution::traits::const_iterator const_iterator; + const_iterator iter, iterBegin, iterEnd; + + // loop subsets on fine level + std::vector vParentIndex, vChildIndex; + std::vector vParentDoF, vChildDoF; + for(int si = 0; si < fineDD.num_subsets(); ++si) + { + iterBegin = fineDD.template begin(si); + iterEnd = fineDD.template end(si); + + // loop vertices for fine level subset + for(iter = iterBegin; iter != iterEnd; ++iter) + { + // get element + Vertex* child = *iter; + + // get father + GridObject* parent = mg.get_parent(child); + + // check if child contained in coarseDD. This should always be false + // for a GridLevel::LEVEL, but might be the case for GridLevel::SURFACE + // and an adaptive grid-part used by both dds. In such a case we can + // simply set identity. + if(coarseDD.is_contained(child)){ + // get indices + coarseDD.inner_algebra_indices(child, vParentIndex); + fineDD.inner_algebra_indices(child, vChildIndex); + UG_ASSERT(vParentIndex.size() == vChildIndex.size(), "Size mismatch"); + + // set identity + for(size_t i = 0; i < vParentIndex.size(); ++i) + P(vChildIndex[i], vParentIndex[i]) = 1.0; + + // this child is perfectly handled + continue; + } + else{ + // check if parent exists (this should always be the case, except in + // the case that 'child' is a v-slave) + if(!parent) continue; + + if(!coarseDD.is_contained(parent)){ + UG_THROW("ParticleTransfer: A parent element is not contained in " + " coarse-dd nor the child element in the coarse-dd. " + "This should not happen.") + } + } + + // type of father + const ReferenceObjectID roid = parent->reference_object_id(); + + // loop all components + for(size_t fct = 0; fct < fineDD.num_fct(); fct++) + { + // check that fct defined on subset + if(!fineDD.is_def_in_subset(fct, si)) continue; + + // get global indices + fineDD.inner_dof_indices(child, fct, vChildDoF); + + // detect type of father + switch(roid) + { + case ROID_VERTEX: + { + Vertex* vrt = dynamic_cast(parent); + coarseDD.inner_dof_indices(vrt, fct, vParentDoF); + DoFRef(P, vChildDoF[0], vParentDoF[0]) = 1.0; + } + break; + default: UG_THROW("AssembleStdProlongationForP1Lagrange: Element Father" + "is of unsupported type "< + void ParticleTransfer:: + set_solution_to_zero(vector_type& sol, const int levIndex, const int prtIndex, ConstSmartPtr dd) + { + + typedef typename std::vector::iterator ListIter; + std::vector ElemListLog = m_spCutElementHandler->m_vvvElemListCut[levIndex][prtIndex]; + + for(ListIter listIter = ElemListLog.begin(); listIter != ElemListLog.end(); ++listIter) + { + // collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *m_spCutElementHandler->m_spMG, *listIter); + + // loop vertices + for(size_t v = 0; v < vVertex.size(); ++v) + { + if ( m_spCutElementHandler->m_spInterfaceVrtMarker->is_marked(vVertex[v]) ) + { + // loop velocity DoFs + for (size_t fct = 0; fct < dim; ++fct) + { + // create multi index + std::vector vInd; + // get multi indices + if(dd->inner_dof_indices(vVertex[v], fct, vInd) != 1) + UG_THROW("Only one index expected."); + + // set velocity solution in FlatTopVrt to zero + DoFRef(sol, vInd[0]) = 0.0; + } + } + + } // end vrt-loop + } // end cutElem-loop + + } + + template + void ParticleTransfer:: + adjust_prolongation(vector_type& corrFine, GridLevel fineLvl, + const vector_type& corrCoarse, GridLevel coarseLvl, + ConstSmartPtr > spApproxSpace) + { + const int coarseIndex = m_spCutElementHandler->get_Index(coarseLvl); + const int fineIndex = m_spCutElementHandler->get_Index(fineLvl); + + size_t numPrt = m_spCutElementHandler->num_particles(); + for(size_t p = 0; p < numPrt; ++p) + { + +#ifdef UG_PARALLEL + std::vector< grid_base_object* > ElemList = m_spCutElementHandler->m_vvvElemListCut[fineIndex][p]; + if( ElemList.size() == 0 ) + continue; +#endif + /////////////////////////////////////////////////////////// + // 1) projection of the defect of extrapolated ghost vrt: + //////////////////////////////////////////////////////////// + + ConstSmartPtr ddFine = spApproxSpace->dof_distribution(fineLvl); + set_solution_to_zero(corrFine, fineIndex, p, ddFine); + + /////////////////////////////////////////////////////////// + // 2) injection for extraDoFs: + //////////////////////////////////////////////////////////// + std::vector transIndCoarse = m_spCutElementHandler->get_transInd(coarseIndex, p); + std::vector rotIndCoarse = m_spCutElementHandler->get_rotInd(coarseIndex, p); + + std::vector transIndFine = m_spCutElementHandler->get_transInd(fineIndex, p); + std::vector rotIndFine = m_spCutElementHandler->get_rotInd(fineIndex, p); + + for ( int d = 0; d < dim; ++d ) + { + DoFRef(corrFine, transIndFine[d]) = DoFRef(corrCoarse, transIndCoarse[d]); + DoFRef(corrFine, rotIndFine[d]) = DoFRef(corrCoarse, rotIndCoarse[d]); + } + } + + + } + + + template + void ParticleTransfer:: + adjust_restriction(vector_type& dCoarse, GridLevel coarseLvl, + const vector_type& dFine, GridLevel fineLvl, + ConstSmartPtr > spApproxSpace) + { + // UG_LOG("nothing...\n"); + + ConstSmartPtr ddCoarse = spApproxSpace->dof_distribution(coarseLvl); + ConstSmartPtr ddFine = spApproxSpace->dof_distribution(coarseLvl); + + const int coarseIndex = m_spCutElementHandler->get_Index(coarseLvl,ddCoarse); + const int fineIndex = m_spCutElementHandler->get_Index(fineLvl,ddFine); + + size_t numPrt = m_spCutElementHandler->num_particles(); + // loop over all particles and initialize defects: + for(size_t p = 0; p < numPrt; ++p) + { + +#ifdef UG_PARALLEL + std::vector< grid_base_object* > ElemList = m_spCutElementHandler->m_vvvElemListCut[fineIndex][p]; + if( ElemList.size() == 0 ) + continue; +#endif + + /////////////////////////////////////////////////////////// + // 1) set solution outside fluid to zero: + //////////////////////////////////////////////////////////// + + set_solution_to_zero(dCoarse, coarseIndex, p, ddCoarse); + + /////////////////////////////////////////////////////////// + // 2) injection for extraDoFs: + //////////////////////////////////////////////////////////// + std::vector transIndCoarse = m_spCutElementHandler->get_transInd(coarseIndex, p); + std::vector rotIndCoarse = m_spCutElementHandler->get_rotInd(coarseIndex, p); + + std::vector transIndFine = m_spCutElementHandler->get_transInd(fineIndex, p); + std::vector rotIndFine = m_spCutElementHandler->get_rotInd(fineIndex, p); + + for ( int d = 0; d < dim; ++d ) + { + DoFRef(dCoarse, transIndCoarse[d]) = DoFRef(dFine, transIndFine[d]); + DoFRef(dCoarse, rotIndCoarse[d]) = DoFRef(dFine, rotIndFine[d]); + } + + } + + } + + + template + size_t ParticleTransfer:: + get_vertex_index(Vertex* vrt, GridObject* elem) + { + std::vector vVertex; + CollectVertices(vVertex, *m_spCutElementHandler->m_spMG, elem); + + for(size_t i = 0; i < vVertex.size(); ++i) + if ( vrt == vVertex[i]) + return i; + + UG_THROW("in CutElementHandler_TwoSided::get_vertex_index: no index found!\n"); + } + + + template + size_t ParticleTransfer:: + get_vertex_mode(Vertex* coarseVrt0, Vertex* coarseVrt1, Vertex* childVrt ) + { + ////////////////////////////////////////////////////////// + // alpha = (0.5, 0.5) => mode = 0 + // alpha = (0.0, 0.0) => mode = 1 + // alpha = (1.0, 0.0) => mode = 2 + // alpha = new weight => mode = 3 + ////////////////////////////////////////////////////////// + + bool bCoarseVrt0_isInside = false; + bool bCoarseVrt1_isInside = false; + bool bChildVrt_isInside = false; + + + if ( !m_spCutElementHandler->m_spOutsideMarker->is_marked(coarseVrt0) && !m_spCutElementHandler->m_spInterfaceVrtMarker->is_marked(coarseVrt0)) + bCoarseVrt0_isInside = true; + if ( !m_spCutElementHandler->m_spOutsideMarker->is_marked(coarseVrt1) && !m_spCutElementHandler->m_spInterfaceVrtMarker->is_marked(coarseVrt1)) + bCoarseVrt1_isInside = true; + if ( !m_spCutElementHandler->m_spOutsideMarker->is_marked(childVrt) && !m_spCutElementHandler->m_spInterfaceVrtMarker->is_marked(childVrt)) + bChildVrt_isInside = true; + + int prtIndex = -1; + bool isOutside_vrt0 = m_spCutElementHandler->is_outsideFluid(prtIndex, coarseVrt0); + bool isOutside_vrt1 = m_spCutElementHandler->is_outsideFluid(prtIndex, coarseVrt1); + + if ( m_spCutElementHandler->m_spOutsideMarker->is_marked(coarseVrt0) && !isOutside_vrt0 ) + UG_THROW("inconsistent 0!\n"); + if ( !m_spCutElementHandler->m_spOutsideMarker->is_marked(coarseVrt0) && isOutside_vrt0 ) + UG_THROW("inconsistent 1!\n"); + if ( m_spCutElementHandler->m_spOutsideMarker->is_marked(coarseVrt1) && !isOutside_vrt1 ) + UG_THROW("inconsistent 2!\n"); + if ( !m_spCutElementHandler->m_spOutsideMarker->is_marked(coarseVrt1) && isOutside_vrt1 ) + UG_THROW("inconsistent 3!\n"); + + // inside edge => alpha = (0.5, 0.5) + if ( bCoarseVrt0_isInside && bCoarseVrt1_isInside) + return 0; + // edge cutted by interface => alpha = (0.5, 0.5) OR (1.0, 0.0) OR alphaNew! + // both interface nodes => alpha = (0.5,0.5) for pressure, for vel: reset later during adjust_prolongation: + else if ( m_spCutElementHandler->m_spInterfaceVrtMarker->is_marked(coarseVrt0) && m_spCutElementHandler->m_spInterfaceVrtMarker->is_marked(coarseVrt1) ) + return 0; + // outside edge => alpha = (0.0, 0.0) + else if ( m_spCutElementHandler->m_spOutsideMarker->is_marked(coarseVrt0) && m_spCutElementHandler->m_spOutsideMarker->is_marked(coarseVrt1) ) + return 1; + else if ( !m_spCutElementHandler->m_spInterfaceVrtMarker->is_marked(coarseVrt0) && !m_spCutElementHandler->m_spInterfaceVrtMarker->is_marked(coarseVrt1) ) + {UG_THROW("error in 'particle_transfer_impl:get_vertex_mode': one vertex must be 'on interface'!\n");} + + // check: exactly one vertex must be inside: + else if ( !bCoarseVrt0_isInside && !bCoarseVrt1_isInside ) + {UG_THROW("error in 'particle_transfer_impl:get_vertex_mode': one vertex must be inside!\n");} + // if one vertex is inside, BUT the FlatTopVertex is also ON interface: (0.5, 0.5) ! + else if ( m_spCutElementHandler->m_spNearInterfaceVrtMarker->is_marked(coarseVrt0) || m_spCutElementHandler->m_spNearInterfaceVrtMarker->is_marked(coarseVrt1) ) + { + /* std::vector vParentDoF; + coarseDD.inner_dof_indices(coarseVrt0, 0, vParentDoF); + if ( m_spCutElementHandler->m_spNearInterfaceVrtMarker.is_marked(coarseVrt0) ) + UG_THROW("oho 0: vParentDoF = " << vParentDoF[0] << "\n"); + coarseDD.inner_dof_indices(coarseVrt1, 0, vParentDoF); + if ( m_spCutElementHandler->m_spNearInterfaceVrtMarker.is_marked(coarseVrt1) ) + UG_THROW("oho 1: vParentDoF = " << vParentDoF[0] << "\n");*/ + if ( m_spCutElementHandler->m_spNearInterfaceVrtMarker->is_marked(coarseVrt0) ) + UG_LOG("0 pos: " << m_spCutElementHandler->m_aaPos[coarseVrt0] << "\n"); + + if ( m_spCutElementHandler->m_spNearInterfaceVrtMarker->is_marked(coarseVrt1) ) + UG_LOG("1: pos: " << m_spCutElementHandler->m_aaPos[coarseVrt1] << "\n"); + return 0; + } + // childVertex lies inside => compute new weigthing for prolongation! + else if ( bChildVrt_isInside ) + return 3; + // childVertex lies outside AND on edge cutted by interface => constant prologation for pressure and reset during + // adjust_prolongation for velocity: + else + return 2; + + UG_THROW("error in 'particle_transfer_impl:get_vertex_mode': no case found!\n"); + + } + + +////////////////////////////////////////////////////////// +/// Std-Transfer methods +////////////////////////////////////////////////////////// + +template +void ParticleTransfer:: +assemble_prolongation_p1(matrix_type& P, + const DoFDistribution& fineDD, + const DoFDistribution& coarseDD) +{ + PROFILE_FUNC_GROUP("gmg"); +// allow only lagrange P1 functions + for(size_t fct = 0; fct < fineDD.num_fct(); ++fct) + if(fineDD.lfeid(fct).type() != LFEID::LAGRANGE || + fineDD.lfeid(fct).order() != 1) + UG_THROW("AssembleStdProlongationForP1Lagrange:" + "Interpolation only implemented for Lagrange P1 functions."); + +// resize matrix + P.resize_and_clear(fineDD.num_indices(), coarseDD.num_indices()); + + UG_LOG("begin assemble_prolongation_p1:\n"); + +// iterators + const MultiGrid& mg = *coarseDD.multi_grid(); + typedef DoFDistribution::traits::const_iterator const_iterator; + const_iterator iter, iterBegin, iterEnd; + +// loop subsets on fine level + std::vector vParentIndex, vChildIndex; + std::vector vParentDoF, vChildDoF; + for(int si = 0; si < fineDD.num_subsets(); ++si) + { + iterBegin = fineDD.template begin(si); + iterEnd = fineDD.template end(si); + + // loop vertices for fine level subset + for(iter = iterBegin; iter != iterEnd; ++iter) + { + // get element + Vertex* child = *iter; + + // get father + GridObject* parent = mg.get_parent(child); + + // check if child contained in coarseDD. This should always be false + // for a GridLevel::LEVEL, but might be the case for GridLevel::SURFACE + // and an adaptive grid-part used by both dds. In such a case we can + // simply set identity. + if(coarseDD.is_contained(child)){ + // get indices + coarseDD.inner_algebra_indices(child, vParentIndex); + fineDD.inner_algebra_indices(child, vChildIndex); + UG_ASSERT(vParentIndex.size() == vChildIndex.size(), "Size mismatch"); + + // set identity + for(size_t i = 0; i < vParentIndex.size(); ++i) + P(vChildIndex[i], vParentIndex[i]) = 1.0; + + // this child is perfectly handled + continue; + } + else{ + // check if parent exists (this should always be the case, except in + // the case that 'child' is a v-slave) + if(!parent) continue; + + if(!coarseDD.is_contained(parent)){ + UG_THROW("ParticleTransfer: Parent element \n" + << ElementDebugInfo(mg, parent) << + "is not contained in coarse-dd nor the child element\n" + << ElementDebugInfo(mg, child) << + " in the coarse-dd. This should not happen.") + } + } + + // type of father + const ReferenceObjectID roid = parent->reference_object_id(); + + // loop all components + for(size_t fct = 0; fct < fineDD.num_fct(); fct++) + { + // check that fct defined on subset + if(!fineDD.is_def_in_subset(fct, si)) continue; + + // get global indices + fineDD.inner_dof_indices(child, fct, vChildDoF); + + // detect type of father + switch(roid) + { + case ROID_VERTEX: + { + Vertex* vrt = dynamic_cast(parent); + coarseDD.inner_dof_indices(vrt, fct, vParentDoF); + DoFRef(P, vChildDoF[0], vParentDoF[0]) = 1.0; + } + break; + case ROID_EDGE: + { + Edge* edge = dynamic_cast(parent); + std::vector alpha; + alpha.resize(2,0.5); + + bool newWeights1 = false; + bool newWeights2 = false; + MathVector intersectionPnt; + int prtIndex = -1; + + bool isOutside_vrt0 = m_spCutElementHandler->is_outsideFluid(prtIndex, edge->vertex(0)); + bool isOutside_vrt1 = m_spCutElementHandler->is_outsideFluid(prtIndex, edge->vertex(1)); + size_t vrtInd0 = get_vertex_index(edge->vertex(0), parent); + size_t vrtInd1 = get_vertex_index(edge->vertex(1), parent); + + /* + // output stuff: + std::vector vParentDoF1; + coarseDD.inner_dof_indices(edge->vertex(0), 0, vParentDoF1); + UG_LOG("oho 0: vParentDoF1 = " << vParentDoF1[0] << "\n"); + std::vector vParentDoF2; + coarseDD.inner_dof_indices(edge->vertex(1), 0, vParentDoF2); + UG_LOG("oho 1: vParentDoF2 = " << vParentDoF2[0] << "\n"); + */ + size_t vertexMode = get_vertex_mode(edge->vertex(0), edge->vertex(1), child); + + //bool isOutside_childDoF = m_spCutElementHandler->is_outsideFluid(prtIndex, child); + + + if ( vertexMode == 1 ) + { + alpha[1] = alpha[0] = 0.0; + } + else if ( vertexMode == 2 ) + { + if ( isOutside_vrt0 && isOutside_vrt1 ) + UG_THROW("hmmmm\n"); + if ( isOutside_vrt0 ) + {alpha[1] = 0.0; alpha[0] = 1.0;} + else + {alpha[1] = 1.0; alpha[0] = 0.0;} + } + // only new weighting, if childDoF insideFluid => get boolian isInside_childDoF + else if ( vertexMode == 3 ) //!isOutside_childDoF ) + { + // UG_LOG("vertexMode == 3\n"); + + // case1: vrt0 = insideFluid && vrt1 = outsideFluid: + if ( !isOutside_vrt0 && isOutside_vrt1 ){ + + coarseDD.inner_dof_indices(edge->vertex(1), fct, vParentDoF); + if ( m_spCutElementHandler->is_nearInterfaceVertex(edge->vertex(1), vrtInd1) ) + UG_THROW("1 oho, vParentDoF = " << vParentDoF[0] << "\n"); + + + m_spCutElementHandler->m_spInterfaceProvider->get_intersection_point(intersectionPnt, m_spCutElementHandler->m_aaPos[edge->vertex(0)], m_spCutElementHandler->m_aaPos[edge->vertex(1)], prtIndex, alpha); + newWeights1 = true; + coarseDD.inner_dof_indices(edge->vertex(0), fct, vParentDoF); + // UG_LOG("1: vertex[0] = " << vParentDoF[0] << "\n"); + // UG_LOG("1: alpha = " << alpha[0] << ", " << alpha[1] << "\n"); + // UG_LOG("VORHER: alpha[i] = " << alpha[0] << ", " << alpha[1] << "\n"); + + alpha[0] = 0.5/alpha[0]; + alpha[1] = 1.0 - alpha[0]; + // UG_THROW("NACHHER: alpha[i] = " << alpha[0] << ", " << alpha[1] << "\n"); + } + // case1: vrt0 = outsideFluid && vrt1 = insideFluid: + else if ( isOutside_vrt0 && !isOutside_vrt1 ){ + + coarseDD.inner_dof_indices(edge->vertex(0), fct, vParentDoF); + if ( m_spCutElementHandler->is_nearInterfaceVertex(edge->vertex(0), vrtInd0) ) + UG_THROW("2 oho, vParentDoF = " << vParentDoF[0] << "\n"); + + m_spCutElementHandler->m_spInterfaceProvider->get_intersection_point(intersectionPnt, m_spCutElementHandler->m_aaPos[edge->vertex(1)], m_spCutElementHandler->m_aaPos[edge->vertex(0)], prtIndex, alpha); + newWeights2 = true; + coarseDD.inner_dof_indices(edge->vertex(1), fct, vParentDoF); + // UG_LOG("2: vertex[0] = " << vParentDoF[0] << "\n"); + // UG_LOG("2: alpha[i] = " << alpha[0] << ", " << alpha[1] << "\n"); + // UG_LOG("VORHER: alpha[i] = " << alpha[0] << ", " << alpha[1] << "\n"); + + // switch also ordering of original alpha!!! + alpha[1] = 0.5/alpha[0]; + alpha[0] = 1.0 - alpha[1]; + // UG_THROW("NACHHER: alpha[i] = " << alpha[0] << ", " << alpha[1] << "\n"); + } + else + UG_THROW("vertexMode == 3: hmmm\n"); + + } // end if (vertexMode == 3 ) + else if ( vertexMode != 0 ) + UG_THROW("in particle_transfer_impl.h: no valid vertexMode computed: vertexMode = " << vertexMode << "\n"); + + + for(int i = 0; i < 2; ++i) + { + Edge* edge = dynamic_cast(parent); + coarseDD.inner_dof_indices(edge->vertex(i), fct, vParentDoF); + + // use prtIndices for prolongation if 'isOutside_parentDoF': + bool isOutside_parentDoF = false; + + if ( newWeights2 || newWeights1 ) + isOutside_parentDoF = m_spCutElementHandler->is_outsideFluid(prtIndex, edge->vertex(i)); + + if ( isOutside_parentDoF && fct != dim ) + { + const int coarseIndex = m_spCutElementHandler->get_Index(coarseDD.grid_level()); + + std::vector transIndCoarse = m_spCutElementHandler->get_transInd(coarseIndex, prtIndex); + + std::vector rotIndCoarse = m_spCutElementHandler->get_rotInd(coarseIndex, prtIndex); + + /* UG_LOG("fct = " << fct << "\n"); + UG_LOG("transIndCoarse[0] = " << transIndCoarse[0] << "\n"); + UG_LOG("transIndCoarse[1] = " << transIndCoarse[1] << "\n"); + UG_LOG("transIndCoarse[fct] = " << transIndCoarse[fct] << "\n"); + */ + + // use of 'transIndCoarse[fct]', since 'normally' it is: + // fct == vParentDoF[0][1] + DoFRef(P, vChildDoF[0], transIndCoarse[fct]) = alpha[i]; + DoFRef(P, vChildDoF[0], rotIndCoarse[fct]) = alpha[i]; + // iff NOT 'normal' case: EXIT!! + if ( vParentDoF[0][1] != fct ) + UG_THROW("no natural index mapping => use of incex 'fct' not valid for next operation!\n"); + + } + else + DoFRef(P, vChildDoF[0], vParentDoF[0]) = alpha[i]; + if ( 0 ) //newWeights2 || newWeights1 ) + { + UG_LOG("intersectionPnt = " << intersectionPnt << "\n"); + UG_LOG("i = " << i << "vParentDoF[0] = " << vParentDoF[0] << "\n"); + UG_LOG("i = " << i << "vChildDoF[0] = " << vChildDoF[0] << "\n"); + UG_LOG("alpha[i] = " << alpha[i] << "\n"); + + UG_LOG("DoFRef(P, vChildDoF[0], vParentDoF[0]) = " << DoFRef(P, vChildDoF[0], vParentDoF[0]) << "\n"); + + } + + } + } + break; + case ROID_QUADRILATERAL: + for(int i = 0; i < 4; ++i) + { + Face* face = dynamic_cast(parent); + coarseDD.inner_dof_indices(face->vertex(i), fct, vParentDoF); + DoFRef(P, vChildDoF[0], vParentDoF[0]) = 0.25; + } + break; + case ROID_HEXAHEDRON: + for(int i = 0; i < 8; ++i) + { + Volume* hexaeder = dynamic_cast(parent); + coarseDD.inner_dof_indices(hexaeder->vertex(i), fct, vParentDoF); + DoFRef(P, vChildDoF[0], vParentDoF[0]) = 0.125; + } + break; + default: UG_THROW("AssembleStdProlongationForP1Lagrange: Element father" + " is of unsupported type "<< roid << " for " + << ElementDebugInfo(mg, child) << "."); + } + } + } + } +} +/* +template +void ProjectGlobalPositionToElem(std::vector >& vGlobPos, + GridObject* parent, const TDomain& domain) +{ + const int parentDim = parent->base_object_id(); + + // vertex and full dim parent must match + if(parentDim == 0 || parentDim == TDomain::dim) + return; + +// get the vertices + std::vector > vCornerCoord; + switch(parentDim) + { + case EDGE: + { + CollectCornerCoordinates(vCornerCoord, *static_cast(parent), domain, true); + MathVector dir; + VecSubtract(dir, vCornerCoord[1], vCornerCoord[0]); + for(size_t p = 0; p < vGlobPos.size(); ++p){ + ProjectPointToRay(vGlobPos[p], vGlobPos[p], vCornerCoord[0], dir); + } + } + break; + case FACE: + { + CollectCornerCoordinates(vCornerCoord, *static_cast(parent), domain, true); + MathVector normal; + MathVector a, b; + VecSubtract(a, vCornerCoord[1], vCornerCoord[0]); + VecSubtract(b, vCornerCoord[2], vCornerCoord[0]); + VecCross(normal, a,b); + + for(size_t p = 0; p < vGlobPos.size(); ++p){ + ProjectPointToPlane(vGlobPos[p], vGlobPos[p], vCornerCoord[0], normal); + } + } + break; + default: UG_THROW( "Base Object type not found."); + } +} +*/ + + +template +template +void ParticleTransfer:: +assemble_prolongation(matrix_type& P, + const DoFDistribution& fineDD, + const DoFDistribution& coarseDD, + ConstSmartPtr spDomain) +{ + PROFILE_FUNC_GROUP("gmg"); + +// iterators + MultiGrid& mg = *const_cast(coarseDD.multi_grid().get()); + typedef typename DoFDistribution::traits::const_iterator const_iterator; + const_iterator iter, iterBegin, iterEnd; + +// loop subsets on coarse level + std::vector vParentDoF, vChildDoF; + std::vector vParentIndex, vChildIndex; + for(int si = 0; si < fineDD.num_subsets(); ++si) + { + iterBegin = fineDD.template begin(si); + iterEnd = fineDD.template end(si); + + // check, which cmps to consider on this subset + std::vector vLFEID; + std::vector vFct; + for(size_t fct = 0; fct < fineDD.num_fct(); ++fct){ + if(fineDD.max_fct_dofs(fct, TChild::dim, si) == 0) continue; + vFct.push_back(fct); + vLFEID.push_back(fineDD.lfeid(fct)); + } + if(vFct.empty()) continue; + + // loop elems on coarse level for subset + for(iter = iterBegin; iter != iterEnd; ++iter) + { + // get child + TChild* child = *iter; + + // get parent + GridObject* parent = mg.get_parent(child); + + // check if child contained in coarseDD. This should always be false + // for a GridLevel::LEVEL, but might be the case for GridLevel::SURFACE + // and an adaptive grid-part used by both dds. In such a case we can + // simply set identity. + if(coarseDD.is_contained(child)){ + // get indices + coarseDD.inner_algebra_indices(child, vParentIndex); + fineDD.inner_algebra_indices(child, vChildIndex); + UG_ASSERT(vParentIndex.size() == vChildIndex.size(), "Size mismatch"); + + // set identity + for(size_t i = 0; i < vParentIndex.size(); ++i) + P(vChildIndex[i], vParentIndex[i]) = 1.0; + + // this child is perfectly handled + continue; + } + else{ + + // check if parent exists (this should always be the case, except in + // the case that 'child' is a v-slave) + if(!parent) continue; + + if(!coarseDD.is_contained(parent)){ + UG_THROW("ParticleTransfer: A parent element is not contained in " + " coarse-dd nor the child element in the coarse-dd. " + "This should not happen.") + } + } + + // loop all components + for(size_t f = 0; f < vFct.size(); f++) + { + // get comp and lfeid + const size_t fct = vFct[f]; + const LFEID& lfeID = vLFEID[f]; + + // get global indices + fineDD.inner_dof_indices(child, fct, vChildDoF); + + // switch space type + switch(lfeID.type()) + { + case LFEID::PIECEWISE_CONSTANT: + { + coarseDD.dof_indices(parent, fct, vParentDoF); + UG_ASSERT(vChildDoF.size() == 1, "Must be one."); + UG_ASSERT(vParentDoF.size() == 1, "Must be one."); + + DoFRef(P, vChildDoF[0], vParentDoF[0]) = 1.0; + } + break; + + case LFEID::CROUZEIX_RAVIART: + { + // get dimension of parent + const int parentDim = parent->base_object_id(); + std::vector vParent; + + // check if to interpolate from neighbor elems + if(parentDim == lfeID.dim()){ + // case: Side inner to parent. --> Parent fine. + vParent.push_back(parent); + } else if(parentDim == lfeID.dim() - 1){ + // case: parent is Side. --> Get neighbor elems + typedef typename TChild::sideof TElem; + std::vector vElem; + coarseDD.collect_associated(vElem, parent); + for(size_t p = 0; p < vElem.size(); ++p) + vParent.push_back(vElem[p]); + + } else { + UG_THROW("ParticleTransfer: For CR parent must be full-dim " + "elem or a side (dim-1). But has dim: "< > vDoFPos; + InnerDoFPosition(vDoFPos, child, *spDomain, lfeID); + + // loop contributions from parents + for(size_t i = 0; i < vParent.size(); ++i) + { + // get coarse indices + coarseDD.dof_indices(vParent[i], fct, vParentDoF); + + // get shapes at global positions + std::vector > vvShape; + ShapesAtGlobalPosition(vvShape, vDoFPos, vParent[i], *spDomain, lfeID); + + // add restriction + for(size_t ip = 0; ip < vvShape.size(); ++ip) + for(size_t sh = 0; sh < vvShape[ip].size(); ++sh) + DoFRef(P, vChildDoF[ip], vParentDoF[sh]) += + (1./vParent.size()) * vvShape[ip][sh]; + } + } + break; + + case LFEID::LAGRANGE: + { + // get coarse indices + coarseDD.dof_indices(parent, fct, vParentDoF); + + // global positions of child dofs + std::vector > vDoFPos; + InnerDoFPosition(vDoFPos, child, *spDomain, lfeID); + + // project + // ProjectGlobalPositionToElem(vDoFPos, parent, *spDomain); + + // get shapes at global positions + std::vector > vvShape; + ShapesAtGlobalPosition(vvShape, vDoFPos, parent, *spDomain, lfeID); + + // set restriction + for(size_t ip = 0; ip < vvShape.size(); ++ip) + for(size_t sh = 0; sh < vvShape[ip].size(); ++sh) + DoFRef(P, vChildDoF[ip], vParentDoF[sh]) = vvShape[ip][sh]; + } + break; + + default: + UG_THROW("ParticleTransfer: Local-Finite-Element: "< +void ParticleTransfer:: +assemble_prolongation(matrix_type& P, + const DoFDistribution& fineDD, + const DoFDistribution& coarseDD, + ConstSmartPtr spDomain) +{ + // resize matrix + P.resize_and_clear(fineDD.num_indices(), coarseDD.num_indices()); + + // loop all base types carrying indices on fine elems + if(fineDD.max_dofs(VERTEX)) assemble_prolongation(P, fineDD, coarseDD, spDomain); + if(fineDD.max_dofs(EDGE)) assemble_prolongation(P, fineDD, coarseDD, spDomain); + if(fineDD.max_dofs(FACE)) assemble_prolongation(P, fineDD, coarseDD, spDomain); + if(fineDD.max_dofs(VOLUME)) assemble_prolongation(P, fineDD, coarseDD, spDomain); +} + + +template +template +void ParticleTransfer:: +assemble_restriction(matrix_type& R, + const DoFDistribution& coarseDD, + const DoFDistribution& fineDD, + ConstSmartPtr spDomain) +{ + PROFILE_FUNC_GROUP("gmg"); + +// iterators + MultiGrid& mg = *const_cast(coarseDD.multi_grid().get()); + typedef typename DoFDistribution::traits::const_iterator const_iterator; + const_iterator iter, iterBegin, iterEnd; + +// loop subsets on coarse level + std::vector vParentDoF, vChildDoF; + std::vector vParentIndex, vChildIndex; + for(int si = 0; si < fineDD.num_subsets(); ++si) + { + iterBegin = fineDD.template begin(si); + iterEnd = fineDD.template end(si); + + // check, which cmps to consider on this subset + std::vector vLFEID; + std::vector vFct; + for(size_t fct = 0; fct < fineDD.num_fct(); ++fct){ + if(fineDD.max_fct_dofs(fct, TChild::dim, si) == 0) continue; + vFct.push_back(fct); + vLFEID.push_back(fineDD.lfeid(fct)); + } + if(vFct.empty()) continue; + + // loop elems on coarse level for subset + for(iter = iterBegin; iter != iterEnd; ++iter) + { + // get child + TChild* child = *iter; + + // get parent + GridObject* parent = mg.get_parent(child); + + // check if child contained in coarseDD. This should always be false + // for a GridLevel::LEVEL, but might be the case for GridLevel::SURFACE + // and an adaptive grid-part used by both dds. In such a case we can + // simply set identity. + if(coarseDD.is_contained(child)){ + // get indices + coarseDD.inner_algebra_indices(child, vParentIndex); + fineDD.inner_algebra_indices(child, vChildIndex); + UG_ASSERT(vParentIndex.size() == vChildIndex.size(), "Size mismatch"); + + // set identity + for(size_t i = 0; i < vParentIndex.size(); ++i) + R(vParentIndex[i], vChildIndex[i]) = 1.0; + + // this child is perfectly handled + continue; + } + else{ + + // check if parent exists (this should always be the case, except in + // the case that 'child' is a v-slave) + if(!parent) continue; + + if(!coarseDD.is_contained(parent)){ + UG_THROW("ParticleTransfer: A parent element is not contained in " + " coarse-dd nor the child element in the coarse-dd. " + "This should not happen.") + } + } + + // loop all components + for(size_t f = 0; f < vFct.size(); f++) + { + // get comp and lfeid + const size_t fct = vFct[f]; + const LFEID& lfeID = vLFEID[f]; + + // get global indices + fineDD.inner_dof_indices(child, fct, vChildDoF); + + // switch space type + switch(lfeID.type()) + { + case LFEID::PIECEWISE_CONSTANT: + { + coarseDD.dof_indices(parent, fct, vParentDoF); + UG_ASSERT(vChildDoF.size() == 1, "Must be one."); + UG_ASSERT(vParentDoF.size() == 1, "Must be one."); + + DoFRef(R, vParentDoF[0], vChildDoF[0]) = 1.0; + } + break; + + case LFEID::CROUZEIX_RAVIART: + { + // get dimension of parent + const int parentDim = parent->base_object_id(); + std::vector vParent; + + // check if to interpolate from neighbor elems + if(parentDim == lfeID.dim()){ + // case: Side inner to parent. --> Parent fine. + vParent.push_back(parent); + } else if(parentDim == lfeID.dim() - 1){ + // case: parent is Side. --> Get neighbor elems + typedef typename TChild::sideof TElem; + std::vector vElem; + coarseDD.collect_associated(vElem, parent); + for(size_t p = 0; p < vElem.size(); ++p){ + // NOTE: This is not the transposed of the prolongation + // in adaptive case, since we only restrict to + // covered parts. + if(mg.num_children(vElem[p]) > 0) + vParent.push_back(vElem[p]); + } + + } else { + UG_THROW("ParticleTransfer: For CR parent must be full-dim " + "elem or a side (dim-1). But has dim: "< > vDoFPos; + InnerDoFPosition(vDoFPos, child, *spDomain, lfeID); + + // loop contributions from parents + for(size_t i = 0; i < vParent.size(); ++i) + { + // get coarse indices + coarseDD.dof_indices(vParent[i], fct, vParentDoF); + + // get shapes at global positions + std::vector > vvShape; + ShapesAtGlobalPosition(vvShape, vDoFPos, vParent[i], *spDomain, lfeID); + + // add restriction + for(size_t ip = 0; ip < vvShape.size(); ++ip) + for(size_t sh = 0; sh < vvShape[ip].size(); ++sh) + DoFRef(R, vParentDoF[sh], vChildDoF[ip]) += + (1./vParent.size()) * vvShape[ip][sh]; + } + } + break; + + case LFEID::LAGRANGE: + { + // get coarse indices + coarseDD.dof_indices(parent, fct, vParentDoF); + + // global positions of child dofs + std::vector > vDoFPos; + InnerDoFPosition(vDoFPos, child, *spDomain, lfeID); + + // get shapes at global positions + std::vector > vvShape; + ShapesAtGlobalPosition(vvShape, vDoFPos, parent, *spDomain, lfeID); + + // set restriction + for(size_t ip = 0; ip < vvShape.size(); ++ip) + { + + for(size_t sh = 0; sh < vvShape[ip].size(); ++sh) + { + // vertex on coarse grid which is FT can possibly have no child => injection fails! + // => project average of neighbouring pressure - which is naturally zero in irrelevant vertices:-) + + // global positions of child dofs + std::vector > vDoFPosParent; + InnerDoFPosition(vDoFPosParent, parent, *spDomain, lfeID); + if ( vDoFPosParent.size() == 2 ) + UG_THROW("vDoFPosParent.size() == 2, but = " << vDoFPosParent.size() << "\n"); + + switch(parent->base_object_id()) + { + case VERTEX: + { + const char* filename = "parent_vertex"; + std::string name(filename); + char ext[50]; sprintf(ext, ".txt"); + name.append(ext); + FILE* outputFile = fopen(name.c_str(), "a"); + // create multi index + std::vector vInd; // ToDo: hier std::vector?? + // get multi indices + Vertex* vrt = static_cast(parent); + if(coarseDD.dof_indices(vrt, fct, vInd) != 1) + UG_THROW("Only one index expected."); + if ( m_spCutElementHandler->is_onInterfaceVertex(vrt) ) + { + fprintf(outputFile,"ParentPos: %e \t %e (index = %lu)\n", vDoFPosParent[0][0], vDoFPosParent[0][1], vInd[0][0]); + DoFRef(R, vParentDoF[sh], vChildDoF[ip]) = vvShape[ip][sh]; + } + fclose(outputFile); + + } + break; + case EDGE: + { + + const char* filename = "parent_edge"; + std::string name(filename); + char ext[50]; sprintf(ext, ".txt"); + name.append(ext); + FILE* outputFile = fopen(name.c_str(), "a"); + + Edge* edge = dynamic_cast(parent); + + for ( size_t i = 0; i < 2; ++i ) + { + // create multi index + std::vector vInd; // ToDo: hier std::vector?? + // get multi indices + if(coarseDD.dof_indices(edge->vertex(i), fct, vInd) != 1) + UG_THROW("Only one index expected."); + if ( m_spCutElementHandler->is_onInterfaceVertex(edge->vertex(i)) && vParentDoF[sh][0] == vInd[0][0] ) + { + fprintf(outputFile,"vParentDoF[%lu], vInd[0]: %lu \t %lu \n", i, vParentDoF[sh][0], vInd[0][0]); + DoFRef(R, vParentDoF[sh], vChildDoF[ip]) = vvShape[ip][sh]; + } + } + fclose(outputFile); + + + } + break; + case FACE: UG_THROW("Parent type wrong: Is FACE, but should be always VERTEX for triangular grids!"); break; + case VOLUME: UG_THROW("Parent type wrong: Is VOLUME, but should be always VERTEX for triangular grids!"); break; + default: UG_THROW("Base Object type not found."); + } + // if ( vParentDoF[sh] ) + + } + } + } + break; + + default: + UG_THROW("ParticleTransfer: Local-Finite-Element: "< +void ParticleTransfer:: +assemble_restriction(matrix_type& R, + const DoFDistribution& coarseDD, + const DoFDistribution& fineDD, + ConstSmartPtr spDomain) +{ + // resize matrix + R.resize_and_clear(coarseDD.num_indices(), fineDD.num_indices()); + + // loop all base types carrying indices on fine elems + if(fineDD.max_dofs(VERTEX)) assemble_restriction(R, coarseDD, fineDD, spDomain); + if(fineDD.max_dofs(EDGE)) assemble_restriction(R, coarseDD, fineDD, spDomain); + if(fineDD.max_dofs(FACE)) assemble_restriction(R, coarseDD, fineDD, spDomain); + if(fineDD.max_dofs(VOLUME)) assemble_restriction(R, coarseDD, fineDD, spDomain); +} + + +template +SmartPtr +ParticleTransfer:: +prolongation(const GridLevel& fineGL, const GridLevel& coarseGL, + ConstSmartPtr > spApproxSpace) +{ + UG_LOG("begin prolongation:\n"); + + if(fineGL.level() - coarseGL.level() != 1) + UG_THROW("ParticleTransfer: Can only project between successive level, " + "but fine = "< +SmartPtr +ParticleTransfer:: +restriction(const GridLevel& coarseGL, const GridLevel& fineGL, + ConstSmartPtr > spApproxSpace) +{ + if(fineGL.level() - coarseGL.level() != 1) + UG_THROW("ParticleTransfer: Can only project between successive level, " + "but fine = "< +void ParticleTransfer:: +prolongate(GF& uFine, const GF& uCoarse) +{ + PROFILE_FUNC_GROUP("gmg"); + + if(!bCached) + UG_THROW("ParticleTransfer: currently only cached implemented."); + + const GridLevel& coarseGL = uCoarse.grid_level(); + const GridLevel& fineGL = uFine.grid_level(); + ConstSmartPtr > spApproxSpace = uFine.approx_space(); + if(uCoarse.approx_space() != spApproxSpace) + UG_THROW("ParticleTransfer: cannot prolongate between grid functions from " + "different approximation spaces."); + + try{ + //prolongation(fineGL, coarseGL, spApproxSpace)->apply(uFine, uCoarse); +#ifdef UG_PARALLEL + MatMultDirect(uFine, m_dampProl, *prolongation(fineGL, coarseGL, spApproxSpace), uCoarse); +#else + prolongation(fineGL, coarseGL, spApproxSpace)->axpy(uFine, 0.0, uFine, m_dampProl, uCoarse); +#endif + + // adjust using constraints + for (int type = 1; type < CT_ALL; type = type << 1) + { + for (size_t i = 0; i < m_vConstraint.size(); ++i) + { + if (m_vConstraint[i]->type() & type) + m_vConstraint[i]->adjust_prolongation(uFine, fineGL, uCoarse, coarseGL, type); + } + } + + adjust_prolongation(uFine, fineGL, uCoarse, coarseGL, spApproxSpace); + + } + UG_CATCH_THROW("ParticleTransfer:prolongation: Failed for fine = "< > spApproxSpace = uFine.approx_space(); + if(uCoarse.approx_space() != spApproxSpace) + UG_THROW("ParticleTransfer: cannot prolongate between grid functions from " + "different approximation spaces."); + try{ + + restriction(coarseGL, fineGL, spApproxSpace)-> + apply_ignore_zero_rows(uCoarse, m_dampRes, uFine); + + +// m_spCutElementHandler->plotCoarse(uCoarse); +// m_spCutElementHandler->plotFine(uFine); + + // adjust using constraints + for (int type = 1; type < CT_ALL; type = type << 1) + { + for (size_t i = 0; i < m_vConstraint.size(); ++i) + { + if (m_vConstraint[i]->type() & type) + m_vConstraint[i]->adjust_restriction(uCoarse, coarseGL, uFine, fineGL, type); + } + } + + adjust_restriction(uCoarse, coarseGL, uFine, fineGL, spApproxSpace); + + } UG_CATCH_THROW("ParticleTransfer:do_restrict: Failed for fine = "< > dbgWriter = + m_spDebugWriter.template cast_dynamic >(); + +// check success + if(dbgWriter.invalid()) return; + +// add iter count to name + name.append("_").append(ToString(glTo.level())); + name.append("_").append(ToString(glFrom.level())); + name.append(".mat"); + +// write + GridLevel gridLev = dbgWriter->grid_level(); + dbgWriter->set_grid_levels(glFrom, glTo); + dbgWriter->write_matrix(mat, name.c_str()); + dbgWriter->set_grid_level(gridLev); +} + +} // end namespace ug + +#endif /* __H__UG__LIB_DISC__OPERATOR__LINEAR_OPERATOR__PARTICLE_TRANSFER_IMPL__ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/immersed_interface_base.h b/ugbase/lib_disc/spatial_disc/immersed_util/immersed_interface_base.h new file mode 100644 index 000000000..960a26c6c --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/immersed_interface_base.h @@ -0,0 +1,220 @@ +/* + * immersed_interface_base.h + * + * Created on: 15.01.2015 + * Author: susanne hoellbacher + */ + +#ifndef IMMERSED_INTERFACE_BASE_H_ +#define IMMERSED_INTERFACE_BASE_H_ + +#include "lib_disc/assemble_interface.h" +#include "lib_disc/spatial_disc/local_to_global/local_to_global_mapper.h" +#include "interface_handler/interface_handler_base.h" +#include "lib_disc/spatial_disc/disc_util/fv1Cut_geom.h" +#include "lib_disc/spatial_disc/disc_util/fv1FT_geom.h" + +namespace ug{ + +////////////////////////////////////////////////////////////////////////////////// +// class 'IInterfaceMapper': member of class 'IImmersedInterface' (see below) +// +// it handles the local-to-global mapping, which potentially is changed +// if the additional DoFs on the immersed interface needs to be associated +// to its according entries in the global algebra +// +////////////////////////////////////////////////////////////////////////////////// + +template +class IInterfaceMapper : public ILocalToGlobalMapper +{ + public: + /// Algebra type + typedef TAlgebra algebra_type; + + /// Type of algebra matrix + typedef typename algebra_type::matrix_type matrix_type; + + /// Type of algebra vector + typedef typename algebra_type::vector_type vector_type; + + public: + /// default Constructor + IInterfaceMapper(){}; + + IInterfaceMapper(SmartPtr localHandler); + + /// send local entries to global matrix + virtual void add_local_mat_to_global(matrix_type& mat, const LocalMatrix& lmat, + ConstSmartPtr dd); + virtual void add_local_mat_to_global_interface(matrix_type& mat, const LocalMatrix& lmat, + ConstSmartPtr dd){}; + virtual void add_local_mat_to_global_interface_for2(matrix_type& mat, const LocalMatrix& lmat, + ConstSmartPtr dd){}; + + /// send local entries to global rhs + virtual void add_local_vec_to_global(vector_type& vec, const LocalVector& lvec, + ConstSmartPtr dd); + virtual void add_local_vec_to_global_interface(vector_type& vec, const LocalVector& lvec, + ConstSmartPtr dd){} + virtual void add_local_vec_to_global_interface_for2(vector_type& vec, const LocalVector& lvec, + ConstSmartPtr dd){} + + /// modifies local solution vector for adapted defect computation + virtual void modify_LocalData(LocalMatrix& locJ, LocalVector& locU, + ConstSmartPtr dd){}; + virtual void modify_LocalData(LocalVectorTimeSeries& uT, LocalMatrix& locJ, LocalVector& locU, + ConstSmartPtr dd){}; + + virtual void modify_LocalData(LocalVector& locD, LocalVector& tmpLocD, LocalVector& locU, + ConstSmartPtr dd){}; + virtual void modify_LocalData(LocalVectorTimeSeries& uT, LocalVector& locD, LocalVector& tmpLocD, LocalVector& locU, + ConstSmartPtr dd, size_t t){}; + + /// modifies global solution vector for adapted defect computation + virtual void modify_GlobalSol(vector_type& vecMod, const vector_type& vec, + ConstSmartPtr dd){}; + + virtual void modify_GlobalSol(SmartPtr > vSolMod, + ConstSmartPtr > vSol, + ConstSmartPtr dd){}; + + virtual void set_identity_mat(matrix_type& mat, const LocalMatrix& lmat, + ConstSmartPtr dd); + + /// virtual destructor + virtual ~IInterfaceMapper() {}; + + private: + SmartPtr m_spInterfaceHandlerLocal; + + +}; + +////////////////////////////////////////////////////////////////////////////////// +// class 'IInterfaceBndCond': member of class 'IImmersedInterface' (see below) +// +// class in order to implement boundary conditions on the immersed interface +// it interhits the 'IInterfaceHandlerLocal' class, which provides access +// to all information important for assembling on a cut element, such as +// local indices of DoFs on the interface, size of new local algebra etc. +// +////////////////////////////////////////////////////////////////////////////////// + +template +class IInterfaceBndCond : public IElemDisc +{ + /// world Dimension + static const int dim = TDomain::dim; + + public: + /// defautl constructor + IInterfaceBndCond(const char* functions, const char* subsets, + SmartPtr localHandler); + IInterfaceBndCond(const std::vector& vFct, const std::vector& vSubset, + SmartPtr localHandler); + /// virtual destructor + ~IInterfaceBndCond() {}; +/* + public: + /// type of trial space for each function used + void prepare_setting(const std::vector& vLfeID, bool bNonRegularGrid, bool bStaticRoid) + { UG_THROW("'IInterfaceBndCond::prepare_setting' not implemented!\n"); } + + /// prepares the element loop + template + void prep_elem_loop(const ReferenceObjectID roid, const int si) + { UG_THROW("'IInterfaceBndCond::prep_elem_loop' not implemented!\n"); } + + /// prepares the element for evaluation + template + void prep_elem(const LocalVector& u, GridObject* elem, + const ReferenceObjectID roid, const MathVector vCornerCoords[]) + { UG_THROW("'IInterfaceBndCond::prep_elem' not implemented!\n"); } + + /// finishes the element loop + template + void fsh_elem_loop() + { UG_THROW("'IInterfaceBndCond::fsh_elem_loop' not implemented!\n"); } + + /// adds the stiffness part to the local jacobian + template + void add_jac_A_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, + const MathVector vCornerCoords[]) + { UG_THROW("'IInterfaceBndCond::add_jac_A_elem' not implemented!\n"); } + + /// adds the stiffness part to the local defect + template + void add_def_A_elem(LocalVector& d, const LocalVector& u, GridObject* elem, + const MathVector vCornerCoords[]) + { UG_THROW("'IInterfaceBndCond::add_def_A_elem' not implemented!\n"); } + + template + void add_jac_M_elem(LocalMatrix& J, const LocalVector& u, GridObject* elem, + const MathVector vCornerCoords[]) + { UG_THROW("'IInterfaceBndCond::add_jac_M_elem' not implemented!\n"); } + + template + void add_def_M_elem(LocalVector& d, const LocalVector& u, GridObject* elem, + const MathVector vCornerCoords[]) + { UG_THROW("'IInterfaceBndCond::add_def_M_elem' not implemented!\n"); } + + template + void add_rhs_elem(LocalVector& d, GridObject* elem, const MathVector vCornerCoords[]) + { UG_THROW("'IInterfaceBndCond::add_rhs_elem' not implemented!\n"); } + +*/ + private: + SmartPtr m_spInterfaceHandlerLocal; + +}; + + +////////////////////////////////////////////////////////////////////////////////// +// main class 'IImmersedInterface' +////////////////////////////////////////////////////////////////////////////////// + +template +class IImmersedInterface +{ + public: + /// world Dimension + static const int dim = TDomain::dim; + + /// Algebra type + typedef TAlgebra algebra_type; + + /// Type of algebra matrix + typedef typename algebra_type::matrix_type matrix_type; + + /// Type of algebra vector + typedef typename algebra_type::vector_type vector_type; + + // default constructor + IImmersedInterface(){}; + + IImmersedInterface(SmartPtr > ass, + const char* functions, const char* subsets, + SmartPtr localHandler); + IImmersedInterface(SmartPtr > ass, + const std::vector& vFct, const std::vector& vSubset, + SmartPtr localHandler); + + virtual ~IImmersedInterface() {} + + + private: + + SmartPtr m_spInterfaceHandlerLocal; + SmartPtr > m_spInterfaceMapper; // contains member of class 'IInterfaceHandlerLocal' + SmartPtr > m_spInterfaceBndCond; // contains member of class 'IInterfaceHandlerLocal' + + +}; + + +}// end namespace ug + +#include "immersed_interface_base_impl.h" + +#endif /* IMMERSED_INTERFACE_BASE_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/immersed_interface_base_impl.h b/ugbase/lib_disc/spatial_disc/immersed_util/immersed_interface_base_impl.h new file mode 100644 index 000000000..923ee3847 --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/immersed_interface_base_impl.h @@ -0,0 +1,162 @@ +/* + * immersed_interface_base_impl.h + * + * Created on: 15.01.2015 + * Author: suze + */ + +#ifndef IMMERSED_INTERFACE_BASE_IMPL_ +#define IMMERSED_INTERFACE_BASE_IMPL_ + + +namespace ug{ + +/////////////////////////////////////////////////////////// +// Implementation of the methods class +// 'IInterfaceMapper' +/////////////////////////////////////////////////////////// +template +IInterfaceMapper:: +IInterfaceMapper(SmartPtr localHandler) + : m_spInterfaceHandlerLocal(localHandler) +{ +} + + +template +void IInterfaceMapper:: +set_identity_mat(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd) +{ + const LocalIndices& rowInd = lmat.get_row_indices(); + + for(size_t fct1=0; fct1 < lmat.num_all_row_fct(); ++fct1) + for(size_t dof1=0; dof1 < lmat.num_all_row_dof(fct1); ++dof1) + { + const size_t rowIndex = rowInd.index(fct1,dof1); + const size_t rowComp = rowInd.comp(fct1,dof1); + + BlockRef(mat(rowIndex, rowIndex), rowComp, rowComp) = 1.0; + + } + +} + + +template +void IInterfaceMapper:: +add_local_mat_to_global(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd) +{ + ElementModus modus = m_spInterfaceHandlerLocal->elementModus(); + + switch(modus) + { + case OUTSIDE_DOM: + set_identity_mat(mat, lmat, dd); + break; + case INSIDE_DOM: + AddLocalMatrixToGlobal(mat, lmat); + break; + case CUT_BY_INTERFACE: + add_local_mat_to_global_interface(mat, lmat, dd); + break; + case CUT_BY_2_INTERFACE: + add_local_mat_to_global_interface_for2(mat, lmat, dd); + break; + default: + throw(UGError("Error in IInterfaceMapper::add_local_mat_to_global()!")); + + } + +} + + +template +void IInterfaceMapper:: +add_local_vec_to_global(vector_type& vec, const LocalVector& lvec, ConstSmartPtr dd) +{ + ElementModus modus = m_spInterfaceHandlerLocal->elementModus(); + + switch(modus) + { + case OUTSIDE_DOM: + // add nothing; + break; + case INSIDE_DOM: + AddLocalVector(vec, lvec); + break; + case CUT_BY_INTERFACE: + add_local_vec_to_global_interface(vec, lvec, dd); + break; + case CUT_BY_2_INTERFACE: + add_local_vec_to_global_interface_for2(vec, lvec, dd); + break; + default: + throw(UGError("Error in IInterfaceMapper::add_local_vec_to_global()!")); + + } +} + + +/////////////////////////////////////////////////////////// +// Implementation of the methods class +// 'IInterfaceBndCond' +/////////////////////////////////////////////////////////// + +template +IInterfaceBndCond:: +IInterfaceBndCond(const char* functions, const char* subsets, + SmartPtr localHandler) + : IElemDisc(functions, subsets), + m_spInterfaceHandlerLocal(localHandler) +{ +} + +template +IInterfaceBndCond:: +IInterfaceBndCond(const std::vector& vFct, const std::vector& vSubset, + SmartPtr localHandler) + : IElemDisc(vFct, vSubset), + m_spInterfaceHandlerLocal(localHandler) +{ +} + + +/////////////////////////////////////////////////////////// +// Implementation of the methods class +// 'IImmersedInterface' +/////////////////////////////////////////////////////////// +template +IImmersedInterface:: +IImmersedInterface(SmartPtr > ass, + const char* functions, const char* subsets, + SmartPtr localHandler) + : m_spInterfaceHandlerLocal(localHandler), + m_spInterfaceMapper(new IInterfaceMapper(localHandler)), + m_spInterfaceBndCond(new IInterfaceBndCond(functions, subsets, localHandler)) +{ + + SmartPtr > assAdapt = ass->ass_tuner(); + assAdapt->set_mapping(m_spInterfaceMapper.get()); + +} + +template +IImmersedInterface:: +IImmersedInterface(SmartPtr > ass, + const std::vector& vFct, const std::vector& vSubset, + SmartPtr localHandler) + : m_spInterfaceHandlerLocal(localHandler), + m_spInterfaceMapper(new IInterfaceMapper(localHandler)), + m_spInterfaceBndCond(new IInterfaceBndCond(vFct, vSubset, localHandler)) +{ + + SmartPtr > assAdapt = ass->ass_tuner(); + assAdapt->set_mapping(m_spInterfaceMapper.get()); + +} + + +} // end ug namespace + + +#endif /* IMMERSED_INTERFACE_BASE_IMPL_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/Info File 1 b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/Info File 1 new file mode 100644 index 000000000..4296051dc --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/Info File 1 @@ -0,0 +1,49 @@ +/* Info File for 'InterfaceHandlerLocal' class: */ + +The 'InterfaceHandlerLocal' class acts as a link between the assembling process by the element discretisation 'ElemDisc' and the computations necessary for the immersed interface and by the CutElementHandler. As such, it inherits only local information on the current cut element, involved in the assembly process. + +All assembling of the ElemDisc is cintered around the finite volume/element geometry object 'TFVGeom'. It inherits all local data, like corner coordinates, local indices, ReferenceObjectID. And from that it derives further local data (ip coordinates, normal vectors, gradients) and global data (global corner coordinates, global gradients, global ip coordinates). + +On a cut element, the (finite volume/element) geometry of the element changes from its state in the original mesh. In particular, the coordinates of the corners change and can increase. With that, the cut element can change from a triangle/tetrahedron in the original grid to a quadrilateral/hexagon in the cut geometry (i.e. ReferenceObjectID changes). +Finally, for the local assembling procedures in UG4, due to the changed geometry, also the local indices of the corners need to be adapted and stored. + + + +Main features: + +- NEW LOCAL CORNERS on the cut element: It computes and inherits all coordinates of the cut element corners, i.e. original corners and intersections with the interface. + Stored in: 'm_vCornerCoords' + +- NEW LOCAL INDICES on the cut element: It computes and inherits necessary local index infos for the local assembly process (e.g. for the local-to-global-mapping). + Stored in: 'm_vInterfaceID', 'm_vNOInterfaceID', 'm_vOriginalCornerID' + +- NEW ReferenceObjectID: It inherits the (local) information regarding the ReferenceObjectID (ROID_TRIANGLE, ROID_QUADRILATERAL, ...) + Stored in: 'm_roid' + +- It has access to the cut element infos of the CutElementHandler, e.g. the 'ElementModus'.' + + + +Important methods: +---> update_elem(): called by the 'geo.update()' method of the 'ElemDisc' class. +---> compute_cut_element_data(): calls CollectCorners_...() +---> CollectCorners_...() +---> set_roid_2d/3d() + +Important data: +---> m_vCornerCoords: contains the new and old corners, already orderes appropriately! +---> m_vInterfaceID, m_vNOInterfaceID, v_OriginalCornerID: contains all infos on the local indices + + +Further remarks: + +- The inner boundary faces, which form the linear approximation onto the immersed interface, are stored in the according derived class as 'm_vBF'. Since this object is derived from the finite volume/element geometry, it can not be initialized in the 'InterfaceHandlerLocalBase' class, which does not rely on this specific information. + + --> See e.g. in 'InterfaceHandlerLocalParticle': + typedef typename DimFV1FTGeometry >::BF interfaceBF; + + --> See e.g. in 'InterfaceHandlerLocalDiffusion': + typedef typename DimFV1CutGeometry >::BF interfaceBF; + + + diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/Info File 2 b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/Info File 2 new file mode 100644 index 000000000..03ac35fbd --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/Info File 2 @@ -0,0 +1,103 @@ +/* Info File on the local data provided by the 'InterfaceHandlerLocal' class: */ + +As explained in the 'Info File 1' of this folder, the 'InterfaceHandlerLocal' class computes and holds the following NEW local data on a cut element: + + +- NEW LOCAL CORNERS: Stored in: 'm_vCornerCoords' + +- NEW LOCAL INDICES: Stored in: 'm_vInterfaceID', 'm_vNOInterfaceID', 'm_vOriginalCornerID' + +- NEW ReferenceObjectID: Stored in: 'm_roid' + + + +The 'print_CutElementData()'- method and an according lua-acces enables to print these data into a file for each cut element. + +For explanation of the output let us start with an arbitrary, oiginal element with local numbering of the corners in couterclockwise order as follows: + + 1 _____________ 0 + \ / + \ / + \ / + \ / + \ / + \ / + \ / + 2 + + + +Case 1: The interface cuts the element as follows and the new ReferenceObjectID is ROID_TRIANGLE: + + + 1 _____________ 0 + \ / + \ out / +.....1.........0..... = interface + \ in / + \ / + \ / + \ / + 2 + +--> The two interface corners inherit the local ID of the associated original corners, i.e. 0 and 1. +--> Due to the numbering in counterclockwise order, it is m_vInterfaceID[0] = 0, m_vInterfaceID[1] = 1. + +The output is as follows: + + +------------ ROID_TRIANGLE ---------- + +Cut element corner 0: 9.052746e-01, -3.204833e-02 +Cut element corner 1: 9.041373e-01, -2.846668e-02 +Cut element corner 2: 9.014088e-01, -3.181983e-02 + +Original corner ID: 0 +Original corner ID: 1 +Original corner ID: 2 + +Interface corner ID: 0 +Interface corner ID: 1 + + + + +Case 2: The interface cuts the element as follows and the new ReferenceObjectID is ROID_QUADRILATERAL: + + + 1 _____________ 0 + \ / + \ in / +.....2.........2..... = interface + \ out / + \ / + \ / + \ / + 2 + +--> The two interface corners inherit the local ID of the associated original corner, i.e. 2. +--> Due to the numbering in counterclockwise order, it is m_vInterfaceID[0] = 2, m_vInterfaceID[1] = 3. + + +The output is as follows: + + + +--------- ROID_QUADRILATERAL -------- + +Cut element corner 0: 1.073265e+00, 9.822172e-02 +Cut element corner 1: 1.010256e+00, 1.019461e-01 +Cut element corner 2: 1.011714e+00, 9.931158e-02 +Cut element corner 3: 1.059025e+00, 8.072213e-02 + +Original corner ID: 0 +Original corner ID: 1 +Original corner ID: 2 +Original corner ID: 2 + +Interface corner ID: 2 +Interface corner ID: 3 + + + + diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_base.h b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_base.h new file mode 100644 index 000000000..baec24ec3 --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_base.h @@ -0,0 +1,309 @@ +/* + * interface_handler_local.h + * + * Created on: 15.01.2015 + * Author: suze + */ + +#ifndef INTERFACE_HANDLER_BASE_H_ +#define INTERFACE_HANDLER_BASE_H_ + +#include "lib_grid/multi_grid.h" +#include "../cut_element_handler/cut_element_handler.h" +//#include "../cut_element_handler/cut_element_handler_flat_top.h" +//#include "../cut_element_handler/cut_element_handler_two_sided.h" +#include "../interface_provider/interface_provider_particle.h" + +namespace ug{ + +template +class DimFV1CutGeometry; + + +//////////////////////////////////////////////////////////////////////// +// + +class IInterfaceHandlerLocal +{ + + public: + IInterfaceHandlerLocal() : m_elemModus(INSIDE_DOM){}; + + virtual ~IInterfaceHandlerLocal(){} + + /// access to element modus + ElementModus elementModus(){ return m_elemModus; } + + //////////////////////////////////////////////////////////////////////// + /// virtual class contains all methods which need to be implemented by + /// the class, derived from 'InterfaceHandlerLocalBase' + //////////////////////////////////////////////////////////////////////// + + /// computes the element modus and writes it to 'm_elemModus' + virtual ElementModus get_element_modus(GridObject* elem) + { UG_THROW("in 'IInterfaceHandlerLocal': Missing virtual method: get_element_modus()."); } + + virtual ElementModus compute_element_modus(GridObject* elem) + { UG_THROW("in 'IInterfaceHandlerLocal': Missing virtual method: compute_element_modus()."); } + + virtual bool is_onInterfaceVertex(Vertex* vrt, size_t vrtIndex) + { UG_THROW("in 'IInterfaceHandlerLocal': Missing virtual method: is_onInterfaceVertex()."); } + + virtual bool is_OutsideVertex(Vertex* vrt, size_t vrtIndex) + { UG_THROW("in 'IInterfaceHandlerLocal': Missing virtual method: is_OutsideVertex()."); } + + virtual bool is_nearInterfaceVertex(Vertex* vrt, size_t vrtIndex) + { UG_THROW("in 'IInterfaceHandlerLocal': Missing virtual method: is_nearInterfaceVertex()."); } + + + protected: + /// is actual element inside or outside domain or cut by the interface? + ElementModus m_elemModus; + +}; + +template +class InterfaceHandlerLocalBase : public IInterfaceHandlerLocal +{ + +public: +/// world dimension + static const int dim = TWorldDim; + +/// max number of geometric objects in a dimension +// (most objects in 1 dim, i.e. number of edges, but +1 for 1D) + static const int maxMid = 2*dim + 1; + +/// used traits + typedef fv1_dim_traits traits; + +/// Type of position coordinates + typedef MathVector position_type; + +/// Type of Position Attachment + typedef Attachment position_attachment_type; + +/// Type of Accessor to the Position Data Attachment + typedef Grid::VertexAttachmentAccessor position_accessor_type; + + + InterfaceHandlerLocalBase(SmartPtr > cutElementHandler); + InterfaceHandlerLocalBase(SmartPtr > cutElementHandler); + + virtual ~InterfaceHandlerLocalBase(){} + + /////////////////////////////////////////////////////////////////////////// + /// virtual base class methods: + /////////////////////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + /// central method: update_elem(): + /// it is called during TFVGeom:update() and computes the new cornders + /// i.e. 'vCornerCoords' of the cut element. Based on that ALL local + /// TFVGeom-computations (compute ip's, normals, gradients, ...) follow + /// as for the standard case + + // central method called by TFVGeom:update() + virtual bool update_elem(GridObject* elem, const MathVector* vCornerCoords); + + /// recomputes the 'vCornerCoords' of the cut element and derives 'm_roid' + virtual void compute_cut_element_data(GridObject* elem); + + /// sets data needed for usual computations in case of INSIDE_DOM: 'm_vCornerCoords' and 'm_roid' + virtual void set_element_data(GridObject* elem, const MathVector* vCornerCoords, + ReferenceObjectID roid); + /// computes the 'ElementModus' based on the corners of 'elem' and also sets some BoolMarker + // and cut element data ('VertexModus') in 'CutElementHander' storage + virtual ElementModus compute_element_modus(GridObject* elem) + { return m_spCutElementHandler->compute_element_modus(elem); } + + virtual ElementModus get_element_modus(GridObject* elem) + { return m_spCutElementHandler->get_element_modus(elem); } + + /// updates inner boundary data (called during FV1CutGeom::update()) + virtual void update_inner_boundary(const MathVector* vCornerCoords){}; + virtual void update_inner_boundary_for2(){}; + + + + //////////////////////////////////////////////////////////////// + /// helper methods for 'compute_cut_element_data()': _tools.h + /// ALL methods perform: + /// (1) computation of the new corners of a cut element + /// by computing the intersection with an edge + /// (2) adding the positions to 'vCornerCoords' data of + /// the finite element/volume geometry data storage + //////////////////////////////////////////////////////////////// + + /// collects new corners of the cut element + int CollectCorners_StdFV(GridObject* elem); + int CollectCorners_FlatTop_2d(GridObject* elem); + int CollectCorners_FlatTop_3d(GridObject* elem); + int get_cutMode(std::vector vVertex); + int CollectCorners_FlatTop_Prism3(GridObject* elem); + int CollectCorners_FlatTop_Prism4(GridObject* elem); + int CollectCorners_FlatTop_Pyramid(GridObject* elem); + int CollectCorners_FlatTop_originalTet(GridObject* elem); + + /// helper methods called during 'CollectCorners_FlatTop_2d' to bring the newly computed + // 'vCornerCoords' in correct order (counter clockwise) + void ResortQuadrilateral(std::vector, size_t > > vInsideCorners, + std::vector, size_t > > vOutsideCorners, + MathVector normalDir); + bool isCCW(std::vector > vCornerCoords, MathVector normal); + + // newly computed intersectino points get collected during 'CollectCorners_...()' only, + // if they were not collected before + bool isIncluded(std::vector > vCheckList, MathVector checkPoint); + + ////////////////////////////////////////////////////////////////////// + /// central methods to compute the intersectin with an edge + ////////////////////////////////////////////////////////////////////// + + // computes the 'level-set' value of a point w.r.t. the interface, in order to + // derive its 'VertexModus', i.e. INSIDE, OUTSIDE, ON_INTERFACE + virtual number get_LSvalue_byPosition(MathVector vrtPos) = 0; + + number get_LSvalue(Vertex* vrt) + { return get_LSvalue_byPosition(m_aaPos[vrt]); } + + virtual bool get_intersection_point(MathVector& Intersect, Vertex* vrtOutsideCirc, + Vertex* vrtInsideCirc) = 0; + virtual bool get_intersection_point(MathVector& Intersect, Vertex* vrtOutsideCirc, + Vertex* vrtInsideCirc, std::vector& alphaOut)= 0; + + + ////////////////////////////////////////////////////////// + /// further helper methods in _tools.h + ////////////////////////////////////////////////////////// + + /// for boundary computations + bool lies_onInterface(const size_t newID); + + bool remapped_fromInterface(const size_t origID); + bool remapped_fromInterface(const size_t origID, size_t& get_interfaceID); + bool is_boundary_face(const size_t sideID); + + size_t get_vertex_index(Vertex* vrt, GridObject* elem); + + ////////////////////////////////////////////////////////// + /// access methods + ////////////////////////////////////////////////////////// + + /// access to roid + ReferenceObjectID roid(){ return m_roid; } + + /// access to 'm_vCornerCoords' + const std::vector > corners() const { return m_vCornerCoords; } + const MathVector* pCorners() const { return &m_vCornerCoords[0]; } + + /// access to single entry of 'm_vCornerCoords' + const MathVector corner(size_t i) { return m_vCornerCoords[i]; } + + /// access to 'm_vInterfaceID' + std::vector interface_id_all() { return m_vInterfaceID; } + + /// access to single entry of 'm_vInterfaceID' + size_t interface_id(size_t i) { return m_vInterfaceID[i]; } + + /// access to single entry of 'm_vOriginalCornerID' + const size_t corner_orig(size_t i) const { return m_vOriginalCornerID[i]; } + + /// access to single entry of 'm_vNOInterfaceID' + size_t NOinterface_id(size_t i) { return m_vNOInterfaceID[i]; } + + size_t numCo() { return m_vCornerCoords.size(); } + + + ////////////////////////////////////////////////////////// + /// setter methods + ////////////////////////////////////////////////////////// + + /// writes member 'm_roid' + void set_roid_2d(); + void set_roid_3d(); + + /// called during modify_LocalData()->set_QuadriSol() for case CUT_BY_2_INTERFACE + void set_QuadriSol(LocalVector locD, LocalVector locU) + { m_quadriLocD = locD; m_quadriLocU = locU;} + + void set_StdFV_assembling(bool bValue) { m_bUseStdFVAssembling = bValue; } + bool StdFV_assembling() { return m_bUseStdFVAssembling; } + + void set_print_cutElemData(bool bValue) { m_bPrintCutElemDataToFile = bValue; } + bool print_cutElment_data() { return m_bPrintCutElemDataToFile; } + + // called by FV1Geom during geo.update() of ElemDisc: + void set_orientation(const int orientation) { m_spCutElementHandler->set_orientation(orientation); } + int get_orientation() { return m_spCutElementHandler->get_orientation(); } + + + ////////////////////////////////////////////////////////// + /// output + ////////////////////////////////////////////////////////// + + void print_CutElementData(); + + + /////////////////////////////////////////////////////////////// + /// base members + /////////////////////////////////////////////////////////////// + + //private: + SmartPtr m_spMG; + position_attachment_type m_aPos; /// > m_vCornerCoords; + + /// local indices of interface corners + /// (in case of a remapping onto the original grid nodes, it is the local + /// index of the node accross the interface, lying on the same edge as + /// the interface node + std::vector m_vInterfaceID; + + /// local indices of all not-interface corners + std::vector m_vNOInterfaceID; + + /// maps the new corner indices to the original indices: + /// -> vOriginalCornerID[i] = j => the j-th corner of the original + /// element is associated with the i-th corner of the new element + std::vector m_vOriginalCornerID; + + + /// 4 corners forming the quadrilateral of an element cut by 2 particles + /// ---> REMARK: made sure by CollectCorner-methods, that corner 1,2 belong to prtIndex 0 + /// and corner 3,4 belong to prtIndex 1 + std::vector m_vQuadriOrigID; + LocalVector m_quadriLocD; + LocalVector m_quadriLocU; + + /// for a circular interface and orientation = 1, the + /// inner of the circle belongs to the outside domain + int m_orientationInterface; // default = 1 + + + /// flag for call of CollectCorners_StdFV() + bool m_bUseStdFVAssembling; // default = false + + /// flag for print of cut-element data into file + bool m_bPrintCutElemDataToFile; // default = false + + /// contains radius, center and density of all given particles + SmartPtr > m_spCutElementHandler; + +}; + + + +}// end namespace ug + +#include "interface_handler_base_tools.h" +#include "interface_handler_base_impl.h" + +#endif /* INTERFACE_HANDLER_BASE_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_base_impl.h b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_base_impl.h new file mode 100644 index 000000000..15f55635b --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_base_impl.h @@ -0,0 +1,192 @@ +/* + * interface_handler_local_impl.h + * + * Created on: 19.01.2015 + * Author: suze + */ + +#ifndef INTERFACE_HANDLER_LOCAL_BASE_IMPL_H_ +#define INTERFACE_HANDLER_LOCAL_BASE_IMPL_H_ + + + +namespace ug{ + + +/////////////////////////////////////////////////////////////// +// Constructor +/////////////////////////////////////////////////////////////// +template +InterfaceHandlerLocalBase:: +InterfaceHandlerLocalBase(SmartPtr > cutElementHandler) : + m_spMG(cutElementHandler->m_spMG), + m_roid(ROID_UNKNOWN), + m_bUseStdFVAssembling(false), + m_bPrintCutElemDataToFile(false), + m_spCutElementHandler((SmartPtr >)cutElementHandler) +{ +// get position attachment + m_aPos = GetDefaultPositionAttachment(); + +// let position accessor access Vertex Coordinates + if(!m_spMG->has_attachment(m_aPos)) + m_spMG->attach_to(m_aPos); + m_aaPos.access(*m_spMG, m_aPos); + +// clear member + m_vCornerCoords.clear(); + m_vInterfaceID.clear(); + m_vNOInterfaceID.clear(); + m_vOriginalCornerID.clear(); +} + +template +InterfaceHandlerLocalBase:: +InterfaceHandlerLocalBase(SmartPtr > cutElementHandler) : + m_spMG(cutElementHandler->m_spMG), + m_roid(ROID_UNKNOWN), + m_bUseStdFVAssembling(false), + m_spCutElementHandler((SmartPtr >)cutElementHandler) +{ + // get position attachment + m_aPos = GetDefaultPositionAttachment(); + + // let position accessor access Vertex Coordinates + if(!m_spMG->has_attachment(m_aPos)) + m_spMG->attach_to(m_aPos); + m_aaPos.access(*m_spMG, m_aPos); + + // clear member + m_vCornerCoords.clear(); + m_vInterfaceID.clear(); + m_vNOInterfaceID.clear(); + m_vOriginalCornerID.clear(); +} + + +template +void InterfaceHandlerLocalBase:: +compute_cut_element_data(GridObject* elem) +{ + +// get new element corners and according element type + if ( StdFV_assembling() ) // Version an Stelle von 'm_bUsualAss = true' + { + CollectCorners_StdFV(elem); + + if ( dim == 2 ) set_roid_2d(); + if ( dim == 3 ) set_roid_3d(); + } + else + { + if ( dim == 2 ) { CollectCorners_FlatTop_2d(elem); set_roid_2d(); } + if ( dim == 3 ) { CollectCorners_FlatTop_3d(elem); set_roid_3d(); } + } + + // some checks: + if ( m_vCornerCoords.size() == 0 ) + UG_THROW("m_vCornerCoords.size() = " << m_vCornerCoords.size() << "not possible!\n"); + + if ( dim == 2 ) + if ( elem->reference_object_id() != ROID_TRIANGLE ) + UG_THROW("Discretisation only coded for triangular elements!\n"); + + if ( dim == 3 ) + if ( elem->reference_object_id() != ROID_TETRAHEDRON ) + UG_THROW("Discretisation only coded for tetrahedral elements!\n"); + +// output computed data to file + if ( print_cutElment_data() ) + print_CutElementData(); + +} + +template +void InterfaceHandlerLocalBase:: +set_element_data(GridObject* elem, const MathVector* vCornerCoords, ReferenceObjectID roid) +{ +// for elements, lying inside the domain, set the number of corners +// to the standard case, which is dim+1, since code is only valid +// for Triangles and Tetrahedra + size_t numCo = dim+1; + +// set 'm_vCornerCoords' + m_vCornerCoords.clear(); + for ( size_t i = 0; i < numCo; ++i ) + m_vCornerCoords.push_back(vCornerCoords[i]); + +// set 'm_roid' + m_roid = roid; + +// for OUTSIDE_DOM, also fill 'vOriginalCornerID' and 'vInterfaceID': + m_vInterfaceID.clear(); + m_vOriginalCornerID.clear(); + m_vCornerCoords.clear(); + +// collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *m_spMG, elem); + +// loop vertices and fill cut element data with the usual nodes of the element + for(size_t i = 0; i < vVertex.size(); ++i) + { + // get element + Vertex* vrtRoot = vVertex[i]; + + if ( !is_onInterfaceVertex(vrtRoot, i) ) + { + m_vCornerCoords.push_back(m_aaPos[vrtRoot]); + m_vOriginalCornerID.push_back(i); + } + else + { + m_vCornerCoords.push_back(m_aaPos[vrtRoot]); + m_vOriginalCornerID.push_back(i); + m_vInterfaceID.push_back(m_vCornerCoords.size()-1); // attention: push AFTER 'm_vCornerCoords.push_back()'!! + } + + } + +} + + + +// called by geo.update()!! +template +bool InterfaceHandlerLocalBase:: +update_elem(GridObject* elem, const MathVector* vCornerCoords) +{ + bool do_update_local = false; + +// compute and set the element modus: + m_elemModus = compute_element_modus(elem); + +// m_elemModus = get_element_modus(elem); +// --> not possible to use, since local data will be computed during 'compute_element_modus()' + + switch(m_elemModus) + { + case INSIDE_DOM: if ( dim == 2 ) set_element_data(elem, vCornerCoords, ROID_TRIANGLE); + if ( dim == 3 ) set_element_data(elem, vCornerCoords, ROID_TETRAHEDRON); + break; // usual assembling + case OUTSIDE_DOM: if ( dim == 2 ) set_element_data(elem, vCornerCoords, ROID_TRIANGLE); + if ( dim == 3 ) set_element_data(elem, vCornerCoords, ROID_TETRAHEDRON); + break; // usual assembling + case CUT_BY_INTERFACE: compute_cut_element_data(elem); + //if ( m_roid == ROID_PYRAMID )UG_THROW("PYRAMID\n"); + do_update_local = true; + break; // cut element assembling + default: + throw(UGError("Error in InterfaceHandlerLocalBase::update(): switch(m_elemModus)!")); + } + + return do_update_local; + +} + + +} // end ug namespace + + + +#endif /* INTERFACE_HANDLER_LOCAL_BASE_IMPL_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_base_tools.h b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_base_tools.h new file mode 100644 index 000000000..ffe935b30 --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_base_tools.h @@ -0,0 +1,1231 @@ +/* + * interface_handler_local_tools.h + * + * Created on: 19.01.2015 + * Author: suze + */ + +#ifndef INTERFACE_HANDLER_LOCAL_BASE_TOOLS_H_ +#define INTERFACE_HANDLER_LOCAL_BASE_TOOLS_H_ + +namespace ug{ + + +template +bool InterfaceHandlerLocalBase:: +lies_onInterface(const size_t newID) +{ + for ( size_t i = 0; i < m_vInterfaceID.size(); ++i) + if ( m_vInterfaceID[i] == newID ) + return true; + + return false; +} + + +template +bool InterfaceHandlerLocalBase:: +remapped_fromInterface(const size_t origID, size_t& get_interfaceID) +{ + for ( size_t i = 0; i < m_vQuadriOrigID.size(); ++i) + { + size_t origID_of_interface_corners = m_vQuadriOrigID[i]; + if ( origID_of_interface_corners == origID ) + { + get_interfaceID = i; + return true; + } + } + + return false; +} + +template +bool InterfaceHandlerLocalBase:: +remapped_fromInterface(const size_t origID) +{ + for ( size_t i = 0; i < m_vInterfaceID.size(); ++i) + { + size_t interfaceID = m_vInterfaceID[i]; + size_t origID_of_interface_corners = m_vOriginalCornerID[interfaceID]; + if ( origID_of_interface_corners == origID ) + return true; + } + + return false; +} + + +template +bool InterfaceHandlerLocalBase:: +is_boundary_face(const size_t sideID) +{ +// get data + const DimReferenceElement& rRefElem + = ReferenceElementProvider::get(m_roid); + +// number of corners of side (special case bottom side pyramid) + const int coOfSide = (m_roid != ROID_PYRAMID || sideID != 0) + ? rRefElem.num(dim-1, sideID, 0) : rRefElem.num(dim-1, sideID, 0) + 2; + + for(int co = 0; co < coOfSide; ++co) + { + size_t cornerID; + if (m_roid != ROID_PYRAMID || sideID != 0) + cornerID = rRefElem.id(dim-1, sideID, 0, co); + else + cornerID = rRefElem.id(dim-1, sideID, 0, (co % 3) + (co>3 ? 1 : 0)); + + if ( !lies_onInterface(cornerID) ) + return false; + } + + return true; + +} + + +template +void InterfaceHandlerLocalBase:: +set_roid_2d() +{ + size_t numCo = m_vCornerCoords.size(); + + switch(numCo) + { + case 0: m_roid = ROID_UNKNOWN; break; + case 3: m_roid = ROID_TRIANGLE; break; + case 4: m_roid = ROID_QUADRILATERAL; break; + + default: throw(UGError("during switch in 'set_roid_2d()': " + "m_numCo invalid => default case chosen")); + } + +} + +template +void InterfaceHandlerLocalBase:: +set_roid_3d() +{ + size_t numCo = m_vCornerCoords.size(); + + switch(numCo) + { + case 0: m_roid = ROID_UNKNOWN; break; + case 4: m_roid = ROID_TETRAHEDRON; break; + case 5: m_roid = ROID_PYRAMID; break; + case 6: m_roid = ROID_PRISM; break; + + default: throw(UGError("during switch in 'set_roid_3d()': " + "m_numCo invalid => default case chosen")); + } + + +} + +// parameter 'normal' is the direction from the triangle into the inner of the prism +template +bool InterfaceHandlerLocalBase:: +isCCW(std::vector > vCornerCoords, MathVector normal) +{ + + if ( dim != 3 ) + UG_THROW("stop: in 2d the method VecCross() may not be used!\n"); + + MathVector e1, e2; + VecSubtract(e1, vCornerCoords[1], vCornerCoords[0]); + VecSubtract(e2, vCornerCoords[2], vCornerCoords[0]); + + MathVector n; + VecCross(n, e1, e2); + VecNormalize(n,n); + VecNormalize(normal,normal); + + if ( fabs(VecDot(n, normal)) < 1e-6 ) + UG_THROW("in 'isCCW()': vectors are perpendicular.\n"); + + if ( VecDot(n, normal) > 0 ) return true; // CCW + else return false; + +} + +template +bool InterfaceHandlerLocalBase:: +isIncluded(std::vector > vCheckList, MathVector checkPoint) +{ + for(size_t i = 0; i < vCheckList.size(); ++i) + { + bool isEqual = true; + + if ( VecDistance(vCheckList[i],checkPoint) > 1e-10) + isEqual = false; + + if ( isEqual ) + return true; + + } + + return false; +} + +template +void InterfaceHandlerLocalBase:: +ResortQuadrilateral(std::vector, size_t > > vInsideCorners, + std::vector, size_t > > vOutsideCorners, + MathVector normalDir) +{ +// some checks: + if ( vOutsideCorners.size() != 2 ) + UG_THROW("vOutsideCorners.size() has to be 2 in 2d case, but is " + << vOutsideCorners.size() << ".\n"); + if ( vInsideCorners.size() != 2 ) + UG_THROW("vInsideCorners.size() has to be 2 in 2d case, but is " + << vInsideCorners.size() << ".\n"); + if ( vOutsideCorners[0].second != vOutsideCorners[1].second ) + UG_THROW("Outside indices must be identical!\n"); + +//////////////////////////////////////////////////////////////////////////////////////////// +// 1) Copy 'vOutsideCorners'/'vOutsideCorners' to 'm_vCornerCoords' in special order: +// -> ordering: 1. insideCorner, 2./3. outsideCorner, 4. insideCorner +//////////////////////////////////////////////////////////////////////////////////////////// + + m_vCornerCoords.clear(); m_vCornerCoords.resize(4); + m_vOriginalCornerID.clear(); m_vOriginalCornerID.resize(4); +// fill with insideCorners+indices: + m_vCornerCoords[0] = vInsideCorners[0].first; + m_vOriginalCornerID[0] = vInsideCorners[0].second; + + m_vCornerCoords[3] = vInsideCorners[1].first; + m_vOriginalCornerID[3] = vInsideCorners[1].second; + +// fill with outsideCorners+indices: + m_vCornerCoords[1] = vOutsideCorners[0].first; + m_vOriginalCornerID[1] = vOutsideCorners[0].second; + + m_vCornerCoords[2] = vOutsideCorners[1].first; + m_vOriginalCornerID[2] = vOutsideCorners[1].second; + +// remember outside Index in order to fill 'vm_vInterfaceID' after re-ordering. + size_t outInd = vOutsideCorners[0].second; + +//////////////////////////////////////////////////////////////////////////////////////////// +// 2) Check for potential cross-ordering or not-CCW +//////////////////////////////////////////////////////////////////////////////////////////// + MathVector<3> vNormOut1, vNormOut2; + std::vector > vCornerCoordsBlow; vCornerCoordsBlow.resize(4); + for ( size_t i = 0; i < m_vCornerCoords.size(); ++i ) + { + for ( size_t d = 0; d < dim; ++d ) + vCornerCoordsBlow[i][d] = m_vCornerCoords[i][d]; + vCornerCoordsBlow[i][2] = 0.0; + } + + CalculateTriangleNormalNoNormalize(vNormOut1, vCornerCoordsBlow[0], vCornerCoordsBlow[1], vCornerCoordsBlow[2]); + CalculateTriangleNormalNoNormalize(vNormOut2, vCornerCoordsBlow[2], vCornerCoordsBlow[3], vCornerCoordsBlow[0]); + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// Check 1 - cross-ordering +// VecDot(vNormOut1,vNormOut2) < 0 => corners of quadrilateral are not ordered along the +// endges, i.e. across the diagonal => switch order of the two outideCorners, i.e. index [1],[2] +///////////////////////////////////////////////////////////////////////////////////////////////////////// + if ( VecDot(vNormOut1, vNormOut2) < 0 ) + { + MathVector bufferCoord = m_vCornerCoords[1]; + size_t bufferInd = m_vOriginalCornerID[1]; + + m_vCornerCoords[1] = m_vCornerCoords[2]; + m_vOriginalCornerID[1] = m_vOriginalCornerID[2]; + + m_vCornerCoords[2] = bufferCoord; + m_vOriginalCornerID[2] = bufferInd; + } + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// Check 2 - CCW? +// VecDot(vNormOut1,zDir) < 0 => corners of quadrilateral are not CCW: +///////////////////////////////////////////////////////////////////////////////////////////////////////// + for ( size_t i = 0; i < m_vCornerCoords.size(); ++i ) + { + for ( size_t d = 0; d < dim; ++d ) + vCornerCoordsBlow[i][d] = m_vCornerCoords[i][d]; + if ( dim == 2 ) vCornerCoordsBlow[i][2] = 0.0; + + + } + CalculateTriangleNormalNoNormalize(vNormOut1, vCornerCoordsBlow[0], vCornerCoordsBlow[1], vCornerCoordsBlow[2]); + CalculateTriangleNormalNoNormalize(vNormOut2, vCornerCoordsBlow[2], vCornerCoordsBlow[3], vCornerCoordsBlow[0]); + +// some check + if ( VecDot(vNormOut1, vNormOut2) < 0 ) + UG_THROW("check 1 failed after second check!\n"); + + +// pure copy of 'normalDir' data because of data type inconsistence (MathVector<3> vs. MathVector) + MathVector<3> _normalDir; + for ( size_t i = 0; i < 2; ++i ) + _normalDir[i] = normalDir[i]; + if ( dim == 2 ) _normalDir[2] = 1.0; + if ( dim == 3 ) _normalDir[2] = normalDir[2]; + + if ( VecDot(vNormOut1, _normalDir) < 0 ) + { + + MathVector bufferCoord = m_vCornerCoords[1]; + size_t bufferInd = m_vOriginalCornerID[1]; + + m_vCornerCoords[1] = m_vCornerCoords[3]; + m_vOriginalCornerID[1] = m_vOriginalCornerID[3]; + + m_vCornerCoords[3] = bufferCoord; + m_vOriginalCornerID[3] = bufferInd; + } + +// fill 'vInterfaceID': + m_vInterfaceID.clear(); + for ( size_t i = 0; i < m_vOriginalCornerID.size(); ++i ) + if ( m_vOriginalCornerID[i] == outInd ) + m_vInterfaceID.push_back(i); + +} + + + +template +int InterfaceHandlerLocalBase:: +CollectCorners_StdFV(GridObject* elem) +{ +// prepare data + m_vCornerCoords.clear(); + m_vInterfaceID.clear(); + m_vOriginalCornerID.clear(); + +// buffer vectors for (cornerCoords, cornerIndex) + std::vector, size_t > > vOutsideCorners; + std::vector, size_t > > vInsideCorners; + std::vector, size_t > > vNearIntCorners; + +// collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *m_spMG, elem); + +// perform check, whether element is valid for computations (i.e. CUT_BY_INTERFACE) + bool isOutsideVertex = false; + for(size_t i = 0; i < vVertex.size(); ++i) + { + // remember boolian for check, weather there existe at least one vertex, which is FT! + if ( is_OutsideVertex(vVertex[i], i) || is_onInterfaceVertex(vVertex[i], i) ) + { + isOutsideVertex = true; + break; + } + } + if ( !isOutsideVertex ) + UG_THROW("Error in 'CollectCorners_FlatTop_2d': no vertex is FTVertex: should be true for at least 1 vertex!\n"); + + +////////////////////////////////////////////// +// 1) Start filling vector with element corners: +////////////////////////////////////////////// + +// loop vertices + for(size_t i = 0; i < vVertex.size(); ++i) + { + // get element + Vertex* vrtRoot = vVertex[i]; + + ////////////////////////////////////////////// + // case 1: + // vertex inside domain + // => push position and local index to 'vInsideCorners' + if ( !is_onInterfaceVertex(vVertex[i], i) ) + { + if ( is_nearInterfaceVertex(vrtRoot, i) ) + { + UG_THROW("NearInterface BUT !is_FT => neuerdings Fehler!!....\n"); + } + else + { + m_vCornerCoords.push_back(m_aaPos[vrtRoot]); + m_vOriginalCornerID.push_back(i); + + vInsideCorners.push_back(std::make_pair(m_aaPos[vrtRoot], i)); + } + + } + ////////////////////////////////////////////// + // case 2: + // vertex = outside domain + // => push position and local index 'vOutsideCorners' + else + { + m_vCornerCoords.push_back(m_aaPos[vrtRoot]); + m_vOriginalCornerID.push_back(i); + m_vInterfaceID.push_back(m_vCornerCoords.size()-1); // attention: push AFTER 'm_vCornerCoords.push_back()'!! + + vOutsideCorners.push_back(std::make_pair(m_aaPos[vrtRoot], i)); + + } + + } + +// skip whole element, since only interface points are included + if ( dim == 2 && m_vCornerCoords.size() != 3 ) + UG_THROW("in 'CollectCorners_StdFV()': m_vCornerCoords.size() " + "= " << m_vCornerCoords.size() << "not possible!\n"); + if ( dim == 3 && m_vCornerCoords.size() != 4 ) + UG_THROW("in 'CollectCorners_StdFV()': m_vCornerCoords.size() " + "= " << m_vCornerCoords.size() << "not possible!\n"); + + + return m_vCornerCoords.size(); +} + + + +template +size_t InterfaceHandlerLocalBase:: +get_vertex_index(Vertex* vrt, GridObject* elem) +{ + std::vector vVertex; + CollectVertices(vVertex, *this->m_spMG, elem); + + for(size_t i = 0; i < vVertex.size(); ++i) + if ( vrt == vVertex[i]) + return i; + + UG_THROW("in CutElementHandler_TwoSided::get_vertex_index: no index found!\n"); +} + + + + +template +int InterfaceHandlerLocalBase:: +CollectCorners_FlatTop_2d(GridObject* elem) +{ + +// prepare data + m_vCornerCoords.clear(); + m_vInterfaceID.clear(); + m_vOriginalCornerID.clear(); + +// buffer vectors for (cornerCoords, cornerIndex) + std::vector, size_t > > vOutsideCorners; + std::vector, size_t > > vInsideCorners; + std::vector, size_t > > vNearIntCorners; + +// collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *m_spMG, elem); + +// perform check, whether element is valid for computations (i.e. CUT_BY_INTERFACE) + bool isFTVertex = false; + for(size_t i = 0; i < vVertex.size(); ++i) + { + // remember boolian for check, weather there existe at least one vertex, which is FT! + isFTVertex = is_onInterfaceVertex(vVertex[i], i); + if ( isFTVertex ) + break; + } + if ( !isFTVertex ) + UG_THROW("Error in 'CollectCorners_FlatTop_2d': no vertex is FTVertex: should be true for at least 1 vertex!\n"); + +/////////////////////////////////////////////////////////////////////////////// +// 1) Start filling the vector with corners: +/////////////////////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////////////////////// +// REMARK: +// The order is the same as in 'vCornerCoords', therefore we can be sure, that +// the order of the new corners (on the interface) will be consistent with the +// grid standard +/////////////////////////////////////////////////////////////////////////////// + + +// collect all edges of the element + std::vector vEdges; + CollectEdgesSorted(vEdges, *m_spMG, elem); + bool bNearInterface = false; + +// loop vertices + for(size_t i = 0; i < vVertex.size(); ++i) + { + + // get element + Vertex* vrtRoot = vVertex[i]; + + ////////////////////////////////////////////// + // case 1: + // vertex inside domain + // => push position and local index to 'vInsideCorners' + if ( ! is_onInterfaceVertex(vrtRoot, i) ) + { + + if ( is_nearInterfaceVertex(vrtRoot, i) ) + { + UG_THROW("NearInterface BUT !is_FT => neuerdings Fehler!!....\n"); + } + else + { + m_vCornerCoords.push_back(m_aaPos[vrtRoot]); + m_vOriginalCornerID.push_back(i); + + vInsideCorners.push_back(std::make_pair(m_aaPos[vrtRoot], i)); + } + + } + ////////////////////////////////////////////// + // case 2: + // vertex = on interface + near interface + // => no computation of position necessary, since the position of the + // near interface vertex will be taken and its local index + // => push position and local index + else if ( is_nearInterfaceVertex(vrtRoot, i) ) + { + bNearInterface = true; + m_vCornerCoords.push_back(m_aaPos[vrtRoot]); + m_vOriginalCornerID.push_back(i); + m_vInterfaceID.push_back(m_vCornerCoords.size()-1); // attention: push AFTER 'm_vCornerCoords.push_back()'!! + + vOutsideCorners.push_back(std::make_pair(m_aaPos[vrtRoot], i)); + vNearIntCorners.push_back(std::make_pair(m_aaPos[vrtRoot], i)); + + } + ////////////////////////////////////////////// + // case 3: + // vertex = outside domain + // => compute new position: by loop of edges + else + { + ////////////////////////////////////////////////////////////////////////////// + // loop all edges, of which the current vertex (vrtRoot) is part of; if the + // edge is cut of the interface (i.e. the second vrt inside fluid), then + // compute intersection point and store local index + for(size_t e = 0; e < vEdges.size(); ++e) + { + Edge* edge = vEdges[e]; + std::vector vVertexEdge; + CollectVertices(vVertexEdge, *m_spMG, edge); + if ( vVertexEdge.size() != 2 ) + UG_THROW("error in collecting vertices associated to an edge!....EXIT!...\n"); + + Vertex* vrt1 = vVertexEdge[0]; + Vertex* vrt2 = vVertexEdge[1]; + size_t vrtInd1 = get_vertex_index(vrt1, elem); + size_t vrtInd2 = get_vertex_index(vrt2, elem); + + MathVector intersectionPnt; + + /////////////////////////////////////////////////////////////////// + // does vrtRoot lie on a cutted edge? + /////////////////////////////////////////////////////////////////// + // case1: vrtRoot is intersectionPnt with insideCorner = near_interface_corner => remove! + if ( is_nearInterfaceVertex(vrt2, vrtInd2) || is_nearInterfaceVertex(vrt1, vrtInd1) ) + { bNearInterface = true; continue; } + // case2: vrt1 = outside domain && vrt2 = inside domain: + else if ( vrtRoot == vrt1 && !is_onInterfaceVertex(vrt2, vrtInd2) ){ + get_intersection_point(intersectionPnt, vrt2, vrt1); + } + // case3: vrt1 = inside domain && vrt2 = outside domain: + else if ( vrtRoot == vrt2 && !is_onInterfaceVertex(vrt1, vrtInd1) ) + get_intersection_point(intersectionPnt, vrt1, vrt2); + else + continue; + + + // check for correct inersectionPnt + const number threshold_max = -1e+6; + const number LSValue = get_LSvalue_byPosition(intersectionPnt); + if ( fabs(LSValue) > 1e-6 && LSValue != threshold_max ) + UG_THROW("in 'CollectIBCorners2d()': Error in computation of 'intersectionPnt':\n " + " intersectionPnt = " << intersectionPnt << "\n distance from interface = " << LSValue << "\n"); + + + /////////////////////////////////////////////////////////////////// + // only push_back, if not included yet! + // -> can be ONLY the case, if the intersectionPoint is a node + if ( ! isIncluded(m_vCornerCoords, intersectionPnt) ) + { + + m_vCornerCoords.push_back(intersectionPnt); + m_vOriginalCornerID.push_back(i); + m_vInterfaceID.push_back(m_vCornerCoords.size()-1); // attention: push AFTER 'm_vCornerCoords.push_back()'!! + + vOutsideCorners.push_back(std::make_pair(intersectionPnt, i)); + } + + + } // end edge-loop + + } // end else-case + + } // end vrt-loop + +//////////////////////////////////////////////////////////////////////////////////////////// +// Postprecessing for quadrilaterals ( <=> vOutsideCorners == 2 ) +// (vInsideCorners.size() == 2) && (bNearInterface) +// => ALL nodes inside domain, BUT one ON surface +// => no Quadrilateral, but Triangle!! +//////////////////////////////////////////////////////////////////////////////////////////// + + MathVector normalDir(0.0); + if ( (m_vCornerCoords.size() == 4) && (!bNearInterface) && (dim == 2) ) + ResortQuadrilateral(vInsideCorners, vOutsideCorners, normalDir); + else if ( bNearInterface ) + { + // Quadrilateral -> Triangle + if ( vInsideCorners.size() == 1 ) // case 1 + { + // do nothing, since re-sorting not necessary...??? + } + // skip whole element, since only FT points are included + else if ( vInsideCorners.size() == 0 ) + UG_THROW("in 'CollectCorners_FlatTop_2d()': vInsideCorners.size() " + "= " << vInsideCorners.size() << "not possible!\n"); + } + + + return m_vCornerCoords.size(); + +} + +template +int InterfaceHandlerLocalBase:: +CollectCorners_FlatTop_Prism3(GridObject* elem) +{ +/////////////////////////////////////////////////////////////////// +// 1) push_back into 'vInsideCorners' +// 2) collect according outsideCorner (lying on the commom edge) +// 3) push_back into 'vOutsideCorners' +/////////////////////////////////////////////////////////////////// + + bool output = false; + + if ( output ) UG_LOG("_________________________ begin 'CollectIBCorners3d_Prism3()' ______________________________\n\n"); + + m_vCornerCoords.clear(); + m_vInterfaceID.clear(); + m_vOriginalCornerID.clear(); + + std::vector > vOutsideCorners; + std::vector > vInsideCorners; + +// collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *m_spMG, elem); + + // collect all edges of the element + std::vector vEdges; + CollectEdgesSorted(vEdges, *m_spMG, elem); + + // loop vertices + size_t outsideInd; + for(size_t i = 0; i < vVertex.size(); ++i) + { + // get element + Vertex* vrtRoot = vVertex[i]; + + if ( ! is_onInterfaceVertex(vrtRoot, i) ) + { + /////////////////////////////////////////////////////////////////// + // 1) push_back into 'vInsideCorners' + vInsideCorners.push_back(m_aaPos[vrtRoot]); + m_vOriginalCornerID.push_back(i); + + /////////////////////////////////////////////////////////////////// + // 2) collect according outsideCorner (lying on the commom edge) + bool outsideCornerFound = false; + MathVector intersectionPnt; + for(size_t e = 0; e < vEdges.size(); ++e) + { + Edge* edge = vEdges[e]; + std::vector vVertexEdge; + CollectVertices(vVertexEdge, *m_spMG, edge); + if ( vVertexEdge.size() != 2 ) + UG_THROW("in 'NEWcall_Extrapolation': error in collecting vertices associated to an edge!....EXIT!...\n"); + Vertex* vrt1 = vVertexEdge[0]; + Vertex* vrt2 = vVertexEdge[1]; + size_t vrtInd1 = get_vertex_index(vrt1, elem); + size_t vrtInd2 = get_vertex_index(vrt2, elem); + + // lies vrtRoot on a cutted edge? + // case1: vrt1 = outsideParticle && vrt2 = insideParticle: + if ( vrtRoot == vrt1 && is_onInterfaceVertex(vrt2, vrtInd2) ) + {outsideCornerFound = get_intersection_point(intersectionPnt, vrt1, vrt2);} + // case2: vrt2 = outsideParticle && vrt1 = insideParticle: + else if ( vrtRoot == vrt2 && is_onInterfaceVertex(vrt1, vrtInd1) ) + {outsideCornerFound = get_intersection_point(intersectionPnt, vrt2, vrt1);} + // NO nearInterface handling necessary, since this is Pyramid or Tetrahedron case! + else if ( is_nearInterfaceVertex(vrt2, vrtInd2) || is_nearInterfaceVertex(vrt1, vrtInd1) ) + {UG_THROW("in 'CollectCorners_Prism3()': no nearInterface case possible!\n");} + else + continue; + + // check for correct inersectionPnt + const number threshold_max = -1e+6; + const number LSValue = get_LSvalue_byPosition(intersectionPnt); + if ( fabs(LSValue) > 1e-6 && LSValue != threshold_max ) + UG_THROW("in 'CollectIBCorners2d()': Error in computation of 'intersectionPnt':\n " + " intersectionPnt = " << intersectionPnt << "\n distance from interface = " << LSValue << "\n"); + + } // end edge-loop + + if ( !outsideCornerFound ) + UG_THROW("During edge-loop no outsideCorner found!\n"); + + /////////////////////////////////////////////////////////////////// + // 3) push_back into 'vOutsideCorners' + // check for 'isIndluded(), BUT: ALL 3 intersectionPonits need to be included for PRISM!! + if ( isIncluded(vOutsideCorners, intersectionPnt) ) + UG_THROW("intersectionPnt allready included? ERROR\n"); + vOutsideCorners.push_back(intersectionPnt); + + } // end inside-case + else + // recall ousideIndex for 'm_vOriginalCornerID' + outsideInd = i; + + } // end vertex-loop + + for(size_t i = 0; i < 3; ++i) + { + m_vOriginalCornerID.push_back(outsideInd); + m_vInterfaceID.push_back(3+i); + } + +// WRITE 'vCornerCoords': FIRST insideCorners, SECOND outsideCorners + m_vCornerCoords.clear(); + for(size_t i = 0; i < 3; ++i) + m_vCornerCoords.push_back(vInsideCorners[i]); + for(size_t i = 0; i < 3; ++i) + m_vCornerCoords.push_back(vOutsideCorners[i]); + +// some checks: + if ( m_vInterfaceID.size() != 3 ) + UG_THROW("wrong size for m_vInterfaceID! Should be 3 and is " + << m_vInterfaceID.size() << "\n"); + if ( m_vOriginalCornerID.size()!= 6 ) + UG_THROW("wrong size for m_vOriginalCornerID! Should be 6 and is " + << m_vOriginalCornerID.size() << "\n"); + if ( vInsideCorners.size() != 3 ) + UG_THROW("wrong size for vInsideCorners! Should be 3 and is " + << vInsideCorners.size() << "\n"); + if ( vOutsideCorners.size() != 3 ) + UG_THROW("wrong size for vOutsideCorners! Should be 3 and is " + << vOutsideCorners.size() << "\n"); + if ( m_vCornerCoords.size()!= 6 ) + UG_THROW("wrong size for m_vCornerCoords! Should be 6 and is " + << m_vCornerCoords.size() << "\n"); + +// check 'vOutsideCorners'-array for CCW: +// get normal to triangle, built by 'vOutsideCorners'-array: + MathVector normal = vInsideCorners[0]; + VecSubtract(normal, vOutsideCorners[0], normal); + + if ( !isCCW(vOutsideCorners, normal) ) + { + // switch ' m_vCornerCoords' + m_vCornerCoords[4] = vOutsideCorners[2]; + m_vCornerCoords[5] = vOutsideCorners[1]; + // switch ' m_vOriginalCornerID' + size_t buffer = m_vOriginalCornerID[4]; + m_vOriginalCornerID[4] = m_vOriginalCornerID[5]; + m_vOriginalCornerID[5] = buffer; + if ( output ) UG_LOG("SWITCH vOutsideCorneers\n"); + } + +// check 'vInsideCorners'-array for CCW: + if ( !isCCW(vInsideCorners, normal) ) + { + // switch ' m_vCornerCoords' + m_vCornerCoords[1] = vInsideCorners[2]; + m_vCornerCoords[2] = vInsideCorners[1]; + // switch ' m_vOriginalCornerID' + size_t buffer = m_vOriginalCornerID[1]; + m_vOriginalCornerID[1] = m_vOriginalCornerID[2]; + m_vOriginalCornerID[2] = buffer; + if ( output ) UG_LOG("SWITCH vInsideCorneers\n"); + } + + + return m_vCornerCoords.size(); + +} + +template +int InterfaceHandlerLocalBase:: +CollectCorners_FlatTop_Prism4(GridObject* elem) +{ +/////////////////////////////////////////////////////////////////// +// 1) push_back 'insideCorner' into 'm_vCornerCoords' +// 2) collect according outsideCorner (lying on the commom edge) +// 3) push_back 'intersectionPoints' into 'm_vCornerCoords' +// 4) check for CCW-property +/////////////////////////////////////////////////////////////////// + + bool output = false; + if ( output ) UG_LOG("_________________________ begin 'CollectCorners_FlatTop_Prism4()' ______________________________\n\n"); + +// prepare data + m_vCornerCoords.clear(); + m_vInterfaceID.clear(); + m_vOriginalCornerID.clear(); + +// collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *m_spMG, elem); + +// collect all edges of the element + std::vector vEdges; + CollectEdgesSorted(vEdges, *m_spMG, elem); + +// collect outside indices: + std::vector outsideInd; + for(size_t i = 0; i < vVertex.size(); ++i) + if ( is_onInterfaceVertex(vVertex[i], i) ) + outsideInd.push_back(i); + +// some check + if ( outsideInd.size() != 2 ) + UG_THROW("Wrong number of outsideInd!\n"); + + // loop vertices + for(size_t i = 0; i < vVertex.size(); ++i) + { + Vertex* vrtRoot = vVertex[i]; + if ( ! is_onInterfaceVertex(vrtRoot, i) ) + { + /////////////////////////////////////////////////////////////////// + // 1) push_back 'insideCorner' into 'm_vCornerCoords' + m_vCornerCoords.push_back(m_aaPos[vrtRoot]); + m_vOriginalCornerID.push_back(i); + + /////////////////////////////////////////////////////////////////// + // 2) collect according outsideCorner (lying on the commom edge) + MathVector intersectionPnt; + for(size_t e = 0; e < vEdges.size(); ++e) + { + Edge* edge = vEdges[e]; + std::vector vVertexEdge; + CollectVertices(vVertexEdge, *m_spMG, edge); + if ( vVertexEdge.size() != 2 ) + UG_THROW("error in collecting vertices associated to an edge!\n"); + Vertex* vrt1 = vVertexEdge[0]; + Vertex* vrt2 = vVertexEdge[1]; + size_t vrtInd1 = get_vertex_index(vrt1, elem); + size_t vrtInd2 = get_vertex_index(vrt2, elem); + + // lies vrtRoot on a cutted edge? + // case1: vrt1 = outsideParticle && vrt2 = insideParticle: + if ( vrtRoot == vrt1 && is_onInterfaceVertex(vrt2, vrtInd2) ) + { + /////////////////////////////////////////////////////////////////// + // 3) push_back 'intersectionPnt' into 'm_vCornerCoords' + get_intersection_point(intersectionPnt, vrt1, vrt2); + m_vCornerCoords.push_back(intersectionPnt); + + if ( vrt2 == vVertex[outsideInd[0]] ) + m_vOriginalCornerID.push_back(outsideInd[0]); + else if ( vrt2 == vVertex[outsideInd[1]] ) + m_vOriginalCornerID.push_back(outsideInd[1]); + else UG_THROW("No outsideInd found.\n"); + } + // case2: vrt1 = insideParticle && vrt2 = outsideParticle: + else if ( vrtRoot == vrt2 && is_onInterfaceVertex(vrt1, vrtInd1) ) + { + /////////////////////////////////////////////////////////////////// + // 3) push_back 'intersectionPnt' into 'm_vCornerCoords' + get_intersection_point(intersectionPnt, vrt2, vrt1); + m_vCornerCoords.push_back(intersectionPnt); + + if ( vrt1 == vVertex[outsideInd[0]] ) + m_vOriginalCornerID.push_back(outsideInd[0]); + else if ( vrt1 == vVertex[outsideInd[1]] ) + m_vOriginalCornerID.push_back(outsideInd[1]); + else UG_THROW("No outsideInd found.\n"); + } + else + continue; + + // check for correct inersectionPnt + const number threshold_max = -1e+6; + const number LSValue = get_LSvalue_byPosition(intersectionPnt); + if ( fabs(LSValue) > 1e-6 && LSValue != threshold_max ) + UG_THROW("in 'CollectIBCorners2d()': Error in computation of 'intersectionPnt':\n " + " intersectionPnt = " << intersectionPnt << "\n distance from interface = " << LSValue << "\n"); + + } // end edge-loop + } // end inside-case + } // end vertex-loop + + m_vInterfaceID.push_back(1); + m_vInterfaceID.push_back(2); + m_vInterfaceID.push_back(4); + m_vInterfaceID.push_back(5); + + +// some checks: + if ( m_vInterfaceID.size() != 4 ) + UG_THROW("wrong size for m_vInterfaceID! Should be 4 and is " + << m_vInterfaceID.size() << "\n"); + if ( m_vOriginalCornerID.size()!= 6 ) + UG_THROW("wrong size for m_vOriginalCornerID! Should be 6 and is " + << m_vOriginalCornerID.size() << "\n"); + if ( m_vCornerCoords.size()!= 6 ) + UG_THROW("wrong size for m_vCornerCoords! Should be 6 and is " + << m_vCornerCoords.size() << "\n"); + +/////////////////////////////////////////////////////////////////// +// 4) check for CCW-property + std::vector > vTriangleCorners1; + std::vector > vTriangleCorners2; + for(size_t i = 0; i < 3; ++i){ + vTriangleCorners1.push_back(m_vCornerCoords[i]); + vTriangleCorners2.push_back(m_vCornerCoords[3+i]); + } +// get normal to triangle, built by 'vOutsideCorners'-array: + MathVector normal = m_vCornerCoords[0]; + VecSubtract(normal, m_vCornerCoords[3], normal); + + if ( !isCCW(vTriangleCorners1, normal) ) + { + // switch ' m_vCornerCoords' + m_vCornerCoords[1] = vTriangleCorners1[2]; + m_vCornerCoords[2] = vTriangleCorners1[1]; + // switch ' m_vOriginalCornerID' + size_t buffer = m_vOriginalCornerID[1]; + m_vOriginalCornerID[1] = m_vOriginalCornerID[2]; + m_vOriginalCornerID[2] = buffer; + if ( output ) UG_LOG("SWITCH vTriangleCorners1\n"); + + } + +// check 'vInsideCorners'-array for CCW: + if ( !isCCW(vTriangleCorners2, normal) ) + { + // switch ' m_vCornerCoords' + m_vCornerCoords[4] = vTriangleCorners2[2]; + m_vCornerCoords[5] = vTriangleCorners2[1]; + // switch ' m_vOriginalCornerID' + size_t buffer = m_vOriginalCornerID[4]; + m_vOriginalCornerID[4] = m_vOriginalCornerID[5]; + m_vOriginalCornerID[5] = buffer; + if ( output ) UG_LOG("SWITCH vTriangleCorners2\n"); + } + + + return m_vCornerCoords.size(); + +} + +template +int InterfaceHandlerLocalBase:: +CollectCorners_FlatTop_Pyramid(GridObject* elem) +{ +/////////////////////////////////////////////////////////////////// +// 1) push_back into 'vInsideCorners' +// 2) push_back into 'vOutsideCorners' the 2 outsideCorners on a cut edge +// 3) write nearInterfaceCorner on m_vCornerCoords[4], since in this setting it +// is ALWAYS the top of the Pyramid! --> see grid_object_3d.h for ordering! +/////////////////////////////////////////////////////////////////// + + bool output = false; + + if ( output ) + UG_LOG("_________________________ begin 'CollectCorners_FlatTop_Pyramid()' ______________________________\n\n"); + + m_vCornerCoords.clear(); + m_vInterfaceID.clear(); + m_vOriginalCornerID.clear(); + +// buffer vectors for (cornerCoords, cornerIndex) - for application of 'ResortQuadrilateral'! + std::vector, size_t > > vOutsideCorners; + std::vector, size_t > > vInsideCorners; + std::pair, size_t > nearInterfaceData; + +// collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *m_spMG, elem); + + // collect all edges of the element + std::vector vEdges; + CollectEdgesSorted(vEdges, *m_spMG, elem); + + // loop vertices + size_t outsideInd; + for(size_t i = 0; i < vVertex.size(); ++i) + { + Vertex* vrtRoot = vVertex[i]; + + // get nearInterfaceData and directly write cornerCoords to data: + if ( is_nearInterfaceVertex(vrtRoot, i) ) + nearInterfaceData = std::make_pair(m_aaPos[vrtRoot], i); + else if ( ! is_onInterfaceVertex(vrtRoot, i) ) + { + /////////////////////////////////////////////////////////////////// + // 1) push_back into 'vInsideCorners' + vInsideCorners.push_back(std::make_pair(m_aaPos[vrtRoot], i)); + m_vOriginalCornerID.push_back(i); + + /////////////////////////////////////////////////////////////////// + // 2) collect according outsideCorner (lying on the commom edge) + bool outsideCornerFound = false; + MathVector intersectionPnt; + for(size_t e = 0; e < vEdges.size(); ++e) + { + Edge* edge = vEdges[e]; + std::vector vVertexEdge; + CollectVertices(vVertexEdge, *m_spMG, edge); + if ( vVertexEdge.size() != 2 ) + UG_THROW("in 'NEWcall_Extrapolation': error in collecting vertices associated to an edge!....EXIT!...\n"); + Vertex* vrt1 = vVertexEdge[0]; + Vertex* vrt2 = vVertexEdge[1]; + size_t vrtInd1 = get_vertex_index(vrt1, elem); + size_t vrtInd2 = get_vertex_index(vrt2, elem); + + // lies vrtRoot on a cutted edge? + // do nothing for edges with 1 insideCorner and 1 nearInterface corner: + if ( is_nearInterfaceVertex(vrt1,vrtInd1) || is_nearInterfaceVertex(vrt2,vrtInd2) ) + continue; + // case2: vrt1 = outsideParticle && vrt2 = insideParticle: + else if ( vrtRoot == vrt1 && is_onInterfaceVertex(vrt2, vrtInd2) ) + {outsideCornerFound = get_intersection_point(intersectionPnt, vrt1, vrt2);} + // case3: vrt2 = outsideParticle && vrt1 = insideParticle: + else if ( vrtRoot == vrt2 && is_onInterfaceVertex(vrt1, vrtInd1) ) + {outsideCornerFound = get_intersection_point(intersectionPnt, vrt2, vrt1);} + else + continue; + + // check for correct inersectionPnt + const number threshold_max = -1e+6; + const number LSValue = get_LSvalue_byPosition(intersectionPnt); + if ( fabs(LSValue) > 1e-6 && LSValue != threshold_max ) + UG_THROW("in 'CollectIBCorners2d()': Error in computation of 'intersectionPnt':\n " + " intersectionPnt = " << intersectionPnt << "\n distance from interface = " << LSValue << "\n"); + + + } // end edge-loop + + if ( !outsideCornerFound ) + UG_THROW("During edge-loop no outsideCorner found!\n"); + + /////////////////////////////////////////////////////////////////// + // 3) push_back into 'vOutsideCorners' + vOutsideCorners.push_back(std::make_pair(intersectionPnt, 0)); + + } // end inside-case + else + // recall ousideIndex for 'm_vOriginalCornerID' + outsideInd = i; + + } // end vertex-loop + +// some checks: + if ( vInsideCorners.size() != 2 ) + UG_THROW("wrong size for vInsideCorners! Should be 2 and is " + << vInsideCorners.size() << "\n"); + if ( vOutsideCorners.size() != 2 ) + UG_THROW("wrong size for vOutsideCorners! Should be 2 and is " + << vOutsideCorners.size() << "\n"); + + for(size_t i = 0; i < vOutsideCorners.size(); ++i) + vOutsideCorners[i].second = outsideInd; + +// during ResortQuadrilateral: m_vCornerCoords.resize(4) and m_vOriginalCornerID.resize(4)! + MathVector normalDir; + VecSubtract(normalDir, nearInterfaceData.first, vOutsideCorners[0].first); + ResortQuadrilateral(vInsideCorners, vOutsideCorners, normalDir); + + m_vCornerCoords.push_back(nearInterfaceData.first); + m_vOriginalCornerID.push_back(nearInterfaceData.second); + m_vInterfaceID.push_back(4); + +// some checks: + if ( m_vInterfaceID.size() != 3 ) + UG_THROW("wrong size for m_vInterfaceID! Should be 3 and is " + << m_vInterfaceID.size() << "\n"); + if ( m_vOriginalCornerID.size()!= 5 ) + UG_THROW("wrong size for m_vOriginalCornerID! Should be 5 and is " + << m_vOriginalCornerID.size() << "\n"); + if ( m_vCornerCoords.size()!= 5 ) + UG_THROW("wrong size for m_vCornerCoords! Should be 5 and is " + << m_vCornerCoords.size() << "\n"); + + return m_vCornerCoords.size(); + +} + +template +int InterfaceHandlerLocalBase:: +CollectCorners_FlatTop_originalTet(GridObject* elem) +{ +// prepare data + m_vCornerCoords.clear(); + m_vInterfaceID.clear(); + m_vOriginalCornerID.clear(); + +// collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *m_spMG, elem); + + for(size_t i = 0; i < vVertex.size(); ++i) + is_onInterfaceVertex(vVertex[i], i); + +///////////////////////////////////////////////////// +// 1) Start filling vector with cut element corners: +///////////////////////////////////////////////////// + + // loop vertices + for(size_t i = 0; i < vVertex.size(); ++i) + { + // get element + Vertex* vrtRoot = vVertex[i]; + + if ( ! is_onInterfaceVertex(vrtRoot, i) ) + { + if ( is_nearInterfaceVertex(vrtRoot, i) ) + { UG_THROW("NearInterface BUT !is_onInterfaceVertex() => error!\n"); } + else + { + m_vCornerCoords.push_back(m_aaPos[vrtRoot]); + m_vOriginalCornerID.push_back(i); + } + + } + else if ( is_nearInterfaceVertex(vrtRoot, i) ) + { + m_vCornerCoords.push_back(m_aaPos[vrtRoot]); + m_vOriginalCornerID.push_back(i); + m_vInterfaceID.push_back(m_vCornerCoords.size()-1); + } + else + UG_THROW("in 'CollectCorners_FlatTop_originalTet()': outside fluid and NOT nearInterface case not possible!\n"); + } + + return m_vCornerCoords.size(); + +} + +template +int InterfaceHandlerLocalBase:: +get_cutMode(std::vector vVertex) +{ + size_t numOutside = 0; + size_t numNearInterface = 0; + for(size_t i = 0; i < vVertex.size(); ++i) + { + if ( is_onInterfaceVertex(vVertex[i], i) ) + { + numOutside++; + if ( is_nearInterfaceVertex(vVertex[i], i) ) + numNearInterface++; + } + } + + bool logMode = false; + +// if all outside corners are nearInterface, no computation of intersectionPoints +// => purely collecting of corners necessary: + if ( numOutside == numNearInterface ) + { + if ( logMode ) UG_LOG("numOutside = " << numOutside << ", numNearInterface = " << numNearInterface << "\n"); + if ( logMode ) UG_LOG("cutMode = 0\n"); + return 0; // original + } + else if ( numOutside == 1 ) + { + if ( logMode ) UG_LOG("numOutside = " << numOutside << ", numNearInterface = " << numNearInterface << "\n"); + if ( logMode ) UG_LOG("cutMode = 1\n"); + return 1; // Prism3 + } + else if ( numOutside == 2 && numNearInterface == 0 ) + { + if ( logMode ) if ( logMode ) UG_LOG("numOutside = " << numOutside << ", numNearInterface = " << numNearInterface << "\n"); + if ( logMode ) UG_LOG("cutMode = 2\n"); + return 2; // Prism4 + } + else if ( numOutside == 2 && numNearInterface == 1 ) + { + if ( logMode ) UG_LOG("numOutside = " << numOutside << ", numNearInterface = " << numNearInterface << "\n"); + if ( logMode ) UG_LOG("cutMode = 3\n"); + return 3; // Pyramid + } + else if ( numOutside == 3 ) + { + if ( logMode ) UG_LOG("numOutside = " << numOutside << ", numNearInterface = " << numNearInterface << "\n"); + if ( logMode ) UG_LOG("cutMode = 4\n"); + return 4; // Tetrahedron + } + return -1; + +} + +template +int InterfaceHandlerLocalBase:: +CollectCorners_FlatTop_3d(GridObject* elem) +{ +// prepare data + m_vCornerCoords.clear(); + m_vInterfaceID.clear(); + m_vOriginalCornerID.clear(); + +// collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *m_spMG, elem); + + size_t cutMode = get_cutMode(vVertex); + + switch(cutMode) + { + case 0: return CollectCorners_FlatTop_originalTet(elem); // Tetrahedron with 1 corner nearInterface + case 1: return CollectCorners_FlatTop_Prism3(elem); // Prism3 with 3 corners outside + case 2: return CollectCorners_FlatTop_Prism4(elem); // Prism4 with 4 corners outside + case 3: return CollectCorners_FlatTop_Pyramid(elem); // Pyramid with 2 corners outside and 1 corner nearInterface + case 4: return CollectCorners_FlatTop_2d(elem); // Tetrahedron with 3 corners outside + default: { UG_LOG("cutMode = " << cutMode << "\n"); + throw(UGError("Error in calling case dependent CollectIBCorners3d()!")); + } + } + + +} + +template +void InterfaceHandlerLocalBase:: +print_CutElementData() +{ + const char* filename = "CutElementData."; + std::string name(filename); + char ext[50]; sprintf(ext, "txt"); + name.append(ext); + FILE* printFile = fopen(name.c_str(), "a"); + + if ( dim == 3 ) + fprintf(printFile, "--------- New cut element --------\n\n"); + else if ( m_roid == ROID_QUADRILATERAL ) + fprintf(printFile, "--------- ROID_QUADRILATERAL --------\n\n"); + else if ( m_roid == ROID_TRIANGLE ) + fprintf(printFile, "------------ ROID_TRIANGLE ----------\n\n"); + + for ( size_t i = 0; i < m_vCornerCoords.size(); ++i ) + fprintf(printFile,"Cut element corner %lu: %e, %e \n", i, m_vCornerCoords[i][0], m_vCornerCoords[i][1]); + fprintf(printFile,"\n"); + + for(size_t i = 0; i < m_vOriginalCornerID.size(); ++i) + fprintf(printFile,"Original corner ID: %lu\n", m_vOriginalCornerID[i]); + fprintf(printFile,"\n"); + + for(size_t i = 0; i < m_vInterfaceID.size(); ++i) + fprintf(printFile,"Interface corner ID: %lu\n", m_vInterfaceID[i]); + fprintf(printFile,"\n"); + + + fclose(printFile); + +} + +} // end namespace ug + + + +#endif /* INTERFACE_HANDLER_LOCAL_BASE_TOOLS_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_flat_top_cut/Info File b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_flat_top_cut/Info File new file mode 100644 index 000000000..87fab8493 --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_flat_top_cut/Info File @@ -0,0 +1,8 @@ +/* Info File for 'InterfaceHandlerLocalParticle' class: */ + +In addition to the data provided by the base class, the 'InterfaceHandlerLocal' for the moving particle simulation needs to provide infomation on radial data: The discrete scheme for the angular momentum contains the cross product with the radial vector. + +==> Most important new class members: + +- std::vector > m_vRadialAtIP; +- std::vector > m_vRadialAtCo; \ No newline at end of file diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_flat_top_cut/interface_handler_particle.h b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_flat_top_cut/interface_handler_particle.h new file mode 100644 index 000000000..1f76dff90 --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_flat_top_cut/interface_handler_particle.h @@ -0,0 +1,347 @@ +/* + * interface_handler_local.h + * + * Created on: 15.01.2015 + * Author: suze + */ + +#ifndef INTERFACE_HANDLER_LOCAL_PARTICLE_H_ +#define INTERFACE_HANDLER_LOCAL_PARTICLE_H_ + +#include "lib_disc/spatial_disc/disc_util/geom_provider.h" +#include "lib_grid/multi_grid.h" + +#include "../interface_handler_base.h" + +#include + +namespace ug{ + + +template +class DimFV1FTGeometry; + +template +class InterfaceHandlerLocalParticle : public InterfaceHandlerLocalBase +//class FlatTopHandler : public IInterfaceHandlerLocal +{ + + public: + /// world dimension + static const int dim = TWorldDim; + + /// max number of geometric objects in a dimension + // (most objects in 1 dim, i.e. number of edges, but +1 for 1D) + static const int maxMid = DimFV1FTGeometry >::maxNumSCVF + 1; + + /// used traits + typedef fv1_dim_traits traits; + + /// used boundary face type + typedef typename DimFV1FTGeometry >::BF interfaceBF; + + /// Type of position coordinates + typedef MathVector position_type; + + /// Type of Position Attachment + typedef Attachment position_attachment_type; + + /// Type of Accessor to the Position Data Attachment + typedef Grid::VertexAttachmentAccessor position_accessor_type; + + + InterfaceHandlerLocalParticle(SmartPtr > cutElementHandler, + number fluidDensity, number fluidKinVisc); + + + virtual ~InterfaceHandlerLocalParticle() {} + + + ////////////////////////////////////////////////////////////////////////// + /// virtual methods in 'IInterfaceHandlerLocal': need to be impl. here + ////////////////////////////////////////////////////////////////////////// + + // simple forwarding to the associated 'CutElementHandler' class: + + bool is_onInterfaceVertex(Vertex* vrt, size_t vrtIndex = 0) + { return m_spCutElementHandler->is_onInterfaceVertex(vrt, vrtIndex); } + + bool is_OutsideVertex(Vertex* vrt, size_t vrtIndex = 0) + { return m_spCutElementHandler->is_OutsideVertex(vrt, vrtIndex); } + + bool is_nearInterfaceVertex(Vertex* vrt, size_t vrtIndex = 0) + { return m_spCutElementHandler->is_nearInterfaceVertex(vrt, vrtIndex); } + + + ////////////////////////////////////////////////////////////////////////// + /// virtual methods in 'InterfaceHandlerLocalBase': need to be impl. here + ////////////////////////////////////////////////////////////////////////// + + // forwarding to m_spCutElementHandler: + number get_LSvalue_byPosition(MathVector vrtPos) + { return m_spCutElementHandler->get_LSvalue_byPosition(vrtPos); } + + + // forwarding to m_spCutElementHandler: + bool get_intersection_point(MathVector& Intersect, Vertex* vrtOutsideCirc, Vertex* vrtInsideCirc) + { + const int orientation = this->get_orientation(); + + const MathVector& vrtPosOut = this->m_aaPos[vrtOutsideCirc]; + const MathVector& vrtPosIn = this->m_aaPos[vrtInsideCirc]; + + const int prtIndex = get_prtIndex(); + if ( prtIndex == -1 ) UG_THROW("'get_intersection_point()': value of prtIndex not valid!\n"); + + if ( orientation == 1 ) + return m_spCutElementHandler->get_intersection_point(Intersect, vrtPosOut, vrtPosIn, prtIndex); + // inverse order of 'vrtPosOut' and 'vrtPosIn' for call of 'get_intersection_point()' + // to avoid error for alpha < 0: + else if ( orientation == -1 ) + { + return m_spCutElementHandler->get_intersection_point(Intersect, vrtPosIn, vrtPosOut, prtIndex); + } + else + UG_THROW("in InterfaceHandlerLocalDiffusion::get_intersection_point(): orientationInterface not set!\n"); + } + + // forwarding to m_spCutElementHandler: + bool get_intersection_point(MathVector& Intersect, Vertex* vrtOutsideCirc, Vertex* vrtInsideCirc, std::vector& alphaOut) + { + const int orientation = this->get_orientation(); + + const MathVector& vrtPosOut = this->m_aaPos[vrtOutsideCirc]; + const MathVector& vrtPosIn = this->m_aaPos[vrtInsideCirc]; + + const int prtIndex = get_prtIndex(); + if ( prtIndex == -1 ) UG_THROW("'get_intersection_point()': value of prtIndex not valid!\n"); + + if ( orientation == 1 ) + return m_spCutElementHandler->get_intersection_point(Intersect, vrtPosOut, vrtPosIn, prtIndex, alphaOut); + // inverse order of 'vrtPosOut' and 'vrtPosIn' for call of 'get_intersection_point()' + // to avoid error for alpha < 0: + else if ( orientation == -1 ) + { + return m_spCutElementHandler->get_intersection_point(Intersect, vrtPosIn, vrtPosOut, prtIndex, alphaOut); + } + else + UG_THROW("in InterfaceHandlerLocalDiffusion::get_intersection_point(): orientationInterface not set!\n"); + } + + ////////////////////////////////////////////////////////// + /// InterfaceHandlerLocalBase methods + ////////////////////////////////////////////////////////// + + /////////////////////////////////////////////////////////////////////////// + /// central method: update_elem(): + /// it is called during TFVGeom:update() and computes the new cornders + /// i.e. 'vCornerCoords' of the cut element. Based on that ALL local + /// TFVGeom-computations (compute ip's, normals, gradients, ...) follow + /// as for the standard case + bool update(GridObject* elem, const MathVector* vCornerCoords); + + /// re-implement the base class method, since the cut element data does not need to + // be recomputed => herein: call of 'get_element_modus() instead of 'compute_element_modus()' + bool update_elem(GridObject* elem, const MathVector* vCornerCoords) + { + compute_and_set_prtIndex(elem); + return update(elem, vCornerCoords); + } + + // called by FV1FTGeom::update() to fill data 'm_vBF' with the faces on + // the interface + void update_inner_boundary(const MathVector* vCornerCoords) + { + if ( this->StdFV_assembling() ) + update_inner_boundary_radial_StdFV(vCornerCoords); + else + update_inner_boundary_radial(vCornerCoords); + } + + void update_inner_boundary_for2() + { + if ( this->StdFV_assembling() ) + {update_inner_boundary_radial_for2_StdFV();} + else + {update_inner_boundary_radial_for2();} + } + + // new methods for the update of inner boundary faces: + // -> compute the data 'm_vRadialAtIP' and 'm_vRadialAtCo' + // -> in case of a moving particle, the radial direction is needed + // for the computation of the stresses + // -> this data is used in local-to-global-mapper + void update_inner_boundary_radial(const MathVector* vCornerCoords); + void update_inner_boundary_radial_StdFV(const MathVector* vCornerCoords); + + + // REMARK: _for2()-methods not finally tested!! + void update_inner_boundary_radial_for2(); + void update_inner_boundary_radial_for2_StdFV(); + + + ////////////////////////////////////////////////////////// + /// original class methods + helper methods for 'update()' + ////////////////////////////////////////////////////////// + + /// collects all corners of the cut element + int CollectCorners_FlatTop_3d(GridObject* elem); + int get_cutMode(std::vector vVertex); + int CollectCorners_FlatTop_Prism3(GridObject* elem); + int CollectCorners_FlatTop_Prism4(GridObject* elem); + int CollectCorners_FlatTop_Pyramid(GridObject* elem); + int CollectCorners_FlatTop_originalTet(GridObject* elem); + + /// !!! not implemented new => taken from the base class: +/* + void ResortQuadrilateral_for2(std::vector > vQuadriCorners); + + int CollectCorners_StdFV_for2(GridObject* elem); + int CollectCorners_FlatTop_2d_for2(GridObject* elem); + int CollectTriangle_and_Quadri_for2(GridObject* elem, Vertex* vrtInside); + int CollectQuadrilateral_besideTri_for2(GridObject* elem); + int CollectQuadrilateral_for2(GridObject* elem); + + void compute_cut_element_data_for2(GridObject* elem); +*/ + + /////////////////////////////////////////////////////////////// + /// forwarding to 'm_spCutElementHandler' + /////////////////////////////////////////////////////////////// + + int get_prtIndex() { return m_spCutElementHandler->get_prtIndex(); } + int getPrtIndex(size_t dof) { return m_spCutElementHandler->get_prtIndex(dof); } + + void compute_and_set_prtIndex(GridObject* elem) + { m_spCutElementHandler->compute_and_set_prtIndex(elem); } + + /////////////////////////////////////////////////////////////// + /// access to the particle velocities, stored in the + /// 'ParticleProvider' class + + MathVector get_transSol(size_t prtIndex, size_t timeSeriesInd) + { return m_spCutElementHandler->get_transSol(prtIndex, timeSeriesInd); } + MathVector get_rotSol(size_t prtIndex, size_t timeSeriesInd) + { return m_spCutElementHandler->get_rotSol(prtIndex, timeSeriesInd); } + + MathMatrix get_rotationMat(MathVector radialVector) + { return m_spCutElementHandler->get_rotationMat(radialVector); } + + + /////////////////////////////////////////////////////////////// + /// new methods + /////////////////////////////////////////////////////////////// + + /// for boundary computations + bool is_boundary_face_for2(const size_t sideID); + + /// acces to 'm_vQuadriCorners_for2' + const std::vector > quadriCorners() const { return m_vQuadriCorners_for2; } + + // switches the order of storage in 'm_vQuadriCorners_for2' and 'this->m_vQuadriOrigID' + // --> earlier needed during 'CollectQuadrilateral_besideTri_for2()' + // --> currently not needed anymore + void switch_order(); + + + /// called during 'ParticleMapper::modify_LocalData()': + // --> resizes the local data (jacobian and defect) due to + // the potentially increased number of corners of a cut element + void resize_local_indices(LocalVector& locU); + void resize_local_indices(LocalVector& locU, size_t numCo); + + + /////////////////////////////////////////////////////////////// + /// new setter methods + /////////////////////////////////////////////////////////////// + + void set_local_couplings_jac(LocalMatrix rotJ_ind, LocalMatrix rotJ_rot) + { m_rotJ_ind = rotJ_ind; m_rotJ_rot = rotJ_rot; } + + void set_local_couplings_def(LocalVector rotD) + { m_rotD = rotD;} + + /////////////////////////////////////////////////////////////// + /// new getter methods + /////////////////////////////////////////////////////////////// + + SmartPtr > get_particles() { return m_spCutElementHandler->get_particles(); } + size_t num_particles() const { return m_spCutElementHandler->num_particles();} + + number get_density(int prtIndex) { return m_spCutElementHandler->get_density(prtIndex); } + number get_density_fluid() { return m_fluidDensity; } + number get_kinVisc_fluid() { return m_fluidKinVisc; } + MathVector get_center(int prtIndex){ return m_spCutElementHandler->get_center(prtIndex);} + + SmartPtr > get_cutElementHandler() { return m_spCutElementHandler; } + + /// access to single entry of 'm_vRadialAtIP' + MathVector radial_at_ip(size_t i) { return m_vRadialAtIP[i]; } + /// access to single entry of 'm_vRadialAtCo' + MathVector radial_at_co(size_t i) { return m_vRadialAtCo[i]; } + + + std::vector& get_boundary_faces() { return m_vBF; } + const LocalIndices& get_local_indices() const { return m_ind; } + + + /////////////////////////////////////////////////////////////// + /// used in local to global mapper: + number get_rotJ_ind(size_t fct1, size_t dof1, size_t fct2, size_t dof2) + { return m_rotJ_ind(fct1, dof1, fct2, dof2); } + number get_rotJ_rot(size_t fct1, size_t dof1, size_t fct2, size_t dof2) + { return m_rotJ_rot(fct1, dof1, fct2, dof2); } + number get_rotD(size_t fct, size_t dof) + { return m_rotD(fct, dof); } + + + /////////////////////////////////////////////////////////////// + /// data for Particle + /////////////////////////////////////////////////////////////// + + std::vector m_vBF; // updated during FV1FTGeom::update_inner_boundary_faces() + + /// fuid parameter imported by Constructor() + number m_fluidDensity; + number m_fluidKinVisc; + + /// local data for assembling: + LocalMatrix m_rotJ_ind; + LocalMatrix m_rotJ_rot; + LocalVector m_rotD; + + /// size of local algebra for cut element: 'm_numFct' x 'm_numCo' + size_t m_numFct; + + /// number of corners of cut element + size_t m_numCo; + + /// new local algebra for resized cut element + LocalIndices m_ind; + + /// radial data on the interface is needed for the computation of + // the rotational component of the stresses + std::vector > m_vRadialAtIP; // global position of scvf on interface + std::vector > m_vRadialAtCo; // global position of scv on interface + + std::vector > m_vQuadriCorners_for2; + + /// flag for computation of 'm_vRadialAtIP' during call of 'update_inner_boundary_faces()' + const bool m_bRadial_forMassEq_equals_Normal; // default = true + + + /// flag indiating if local data needs to be updated + bool m_bBndDataNeeded; // default = false; + // flag used e.g. in 'FV1FTGeometry::update()' + + + SmartPtr > m_spCutElementHandler; + }; + + +}// end namespace ug + +#include "interface_handler_particle_tools.h" +#include "interface_handler_particle_impl.h" + +#endif /* INTERFACE_HANDLER_LOCAL_PARTICLE_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_flat_top_cut/interface_handler_particle_impl.h b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_flat_top_cut/interface_handler_particle_impl.h new file mode 100644 index 000000000..4cb855ccb --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_flat_top_cut/interface_handler_particle_impl.h @@ -0,0 +1,158 @@ +/* + * interface_handler_local_impl.h + * + * Created on: 19.01.2015 + * Author: suze + */ + +#ifndef INTERFACE_HANDLER_LOCAL_PARTICLE_IMPL_H_ +#define INTERFACE_HANDLER_LOCAL_PARTICLE_IMPL_H_ + + + +namespace ug{ + + +/////////////////////////////////////////////////////////////// +// Constructor +/////////////////////////////////////////////////////////////// +template +InterfaceHandlerLocalParticle:: +InterfaceHandlerLocalParticle(SmartPtr > cutElementHandler, + number fluidDensity, number fluidKinVisc) : + InterfaceHandlerLocalBase(cutElementHandler), + m_fluidDensity(fluidDensity), + m_fluidKinVisc(fluidKinVisc), + m_numFct(0), + m_numCo(0), + m_bRadial_forMassEq_equals_Normal(true), + m_bBndDataNeeded(false), + m_spCutElementHandler(cutElementHandler) +{ + m_vBF.clear(); + m_vRadialAtIP.clear(); + m_vRadialAtCo.clear(); +} + + +template +void InterfaceHandlerLocalParticle:: +resize_local_indices(LocalVector& locU) +{ +// 1. get global indices + m_ind = locU.get_indices(); + m_numFct = m_ind.num_fct(); + m_numCo = this->numCo(); + +// 2. get new local algebra with potentially more indices + m_ind.resize_fct(m_numFct); + // -> here, the original data, i.e. global index information of u.m_pIndex (-> 'u.m_pIndex.m_vvIndex[num_fct][num_dof]'), + // is preserved, and for the new indices, global index = 0 is appended! + for (size_t fct = 0; fct < m_numFct; ++fct) + m_ind.resize_dof(fct, m_numCo); + + return; +} + +template +void InterfaceHandlerLocalParticle::resize_local_indices(LocalVector& locU, size_t numCo) +{ +// 1. get global indices + m_ind = locU.get_indices(); + m_numFct = m_ind.num_fct(); +// m_numCo = numCo; + +// 2. get new local algebra with potentially more indices + m_ind.resize_fct(m_numFct); + // -> here, the original data, i.e. global index information of u.m_pIndex (-> 'u.m_pIndex.m_vvIndex[num_fct][num_dof]'), + // is preserved, and for the new indices, global index = 0 is appended! + for (size_t fct = 0; fct < m_numFct; ++fct) + m_ind.resize_dof(fct, numCo); + + return; +} + + +template +void InterfaceHandlerLocalParticle:: +switch_order() +{ + UG_LOG("============= VOR switch_order ===============\n"); + for ( size_t i = 0; i < this->m_vQuadriOrigID.size(); ++i ) + UG_LOG("buffer_vQuadriOrigID[" << i << "]: " << this->m_vQuadriOrigID[i] << "\n"); + +// A: switch order of 'm_vQuadriCorners_for2' + std::vector > buffer_vCornerCoords; + buffer_vCornerCoords.push_back(m_vQuadriCorners_for2[1]); + buffer_vCornerCoords.push_back(m_vQuadriCorners_for2[0]); + + m_vQuadriCorners_for2.clear(); + m_vQuadriCorners_for2.push_back(buffer_vCornerCoords[0]); + m_vQuadriCorners_for2.push_back(buffer_vCornerCoords[1]); + +// B: switch order of 'm_vQuadriOrigID': + std::vector buffer_vQuadriOrigID; + buffer_vQuadriOrigID.push_back(this->m_vQuadriOrigID[1]); + buffer_vQuadriOrigID.push_back(this->m_vQuadriOrigID[0]); + + this->m_vQuadriOrigID.clear(); + this->m_vQuadriOrigID.push_back(buffer_vQuadriOrigID[0]); + this->m_vQuadriOrigID.push_back(buffer_vQuadriOrigID[1]); + + UG_LOG("============= NACH switch_order ===============\n"); + for ( size_t i = 0; i < this->m_vQuadriOrigID.size(); ++i ) + UG_LOG("m_vQuadriOrigID[" << i << "]: " << this->m_vQuadriOrigID[i] << "\n"); + +} + + +// called by geo.update()!! +template +bool InterfaceHandlerLocalParticle:: +update(GridObject* elem, const MathVector* vCornerCoords) +{ + bool do_update_local = false; + +// needs to be cleared, since it can contain faces from former assembling + m_vBF.clear(); + +// getting cut element modus +// REMARK: In base class, here: call of 'compute_element_modus()' +// instead of 'get_element_modus()'. + this->m_elemModus = this->get_element_modus(elem); // element modus was computed via + // 'compute_element_modus()' during 'update_interface_data()' + + switch(this->m_elemModus) + { + case INSIDE_DOM: if ( dim == 2 ) this->set_element_data(elem, vCornerCoords, ROID_TRIANGLE); + if ( dim == 3 ) this->set_element_data(elem, vCornerCoords, ROID_TETRAHEDRON); + break; // usual assembling + case OUTSIDE_DOM: if ( this->StdFV_assembling() ){ + this->set_element_data(elem, vCornerCoords, ROID_UNKNOWN); + } + else + this->set_element_data(elem, vCornerCoords, ROID_UNKNOWN); + break; + case CUT_BY_INTERFACE: this->compute_cut_element_data(elem); + //if ( this->m_roid == ROID_PYRAMID )UG_THROW("PYRAMID\n"); + do_update_local = true; + break; // cut element assembling +/* case CUT_BY_2_INTERFACE: if ( this->StdFV_assembling() ) + this->compute_cut_element_data(elem); + else + compute_cut_element_data_for2(elem); + do_update_local = true; + break;*/ + default: + throw(UGError("Error in InterfaceHandlerLocalParticle::update(): switch(m_elemModus)!")); + } + + return do_update_local; + +} + +} // end namespace ug + + + +#endif /* INTERFACE_HANDLER_LOCAL_PARTICLE_IMPL_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_flat_top_cut/interface_handler_particle_tools.h b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_flat_top_cut/interface_handler_particle_tools.h new file mode 100644 index 000000000..0aeb51c59 --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_flat_top_cut/interface_handler_particle_tools.h @@ -0,0 +1,413 @@ +/* + * interface_handler_local_tools.h + * + * Created on: 19.01.2015 + * Author: suze + */ + +#ifndef INTERFACE_HANDLER_LOCAL_PARTICLE_TOOLS_H_ +#define INTERFACE_HANDLER_LOCAL_PARTICLE_TOOLS_H_ + +namespace ug{ + + +template +bool InterfaceHandlerLocalParticle:: +is_boundary_face_for2(const size_t sideID) +{ +// REMARK: not finally tested! + UG_THROW("InterfaceHandlerLocalParticle::is_boundary_face_for2(): not finally tested!!!!\n"); + + if ( dim == 3 ) + UG_THROW("in 'is_boundary_face_for2()': only implemented for 2d!!\n"); + +// get data + const DimReferenceElement& rRefElem + = ReferenceElementProvider::get(this->m_roid); + + // number of corners of side (special case bottom side pyramid) + const int coOfSide = (this->m_roid != ROID_PYRAMID || sideID != 0) + ? rRefElem.num(dim-1, sideID, 0) : rRefElem.num(dim-1, sideID, 0) + 2; + + if ( coOfSide > 2 ) + UG_THROW("in 'is_boundary_face_for2()': hmm...coOfSide > 2 ??? \n coOfSide = " << coOfSide << "\n"); + + std::vector prtIndex(2); + + for(int co = 0; co < coOfSide; ++co) + { + size_t cornerID; + if (this->m_roid != ROID_PYRAMID || sideID != 0) + cornerID = rRefElem.id(dim-1, sideID, 0, co); + else + cornerID = rRefElem.id(dim-1, sideID, 0, (co % 3) + (co>3 ? 1 : 0)); + + if ( !this->lies_onInterface(cornerID) ) + return false; + else + prtIndex[co] = getPrtIndex(co); + + } + + + if ( prtIndex[0] == prtIndex[1] ) + { + UG_THROW("========= is_boundary_face = TRUE\n"); + return true; + } + UG_LOG("========= is_boundary_face = FALSE\n"); + + return false; +} + + +template +void InterfaceHandlerLocalParticle:: +update_inner_boundary_radial(const MathVector* vCornerCoords) +{ +// some check + if (dim == 2) { + if (this->m_vBF.size() != 2 && this->m_vBF.size() != 0) + UG_THROW("Error in 'update_inner_boundary_radial()': this->m_vBF.size() != 2:" + << this->m_vBF.size() << "\n"); + } + const int prtIndex = get_prtIndex(); + if (prtIndex == -1) + UG_THROW("InterfaceHandlerLocalParticle::update_inner_boundary_radial(): prtIndex not set!\n"); + +// get data +// we choose the modusIP = 0 and useResized = true +// --> see implemenation and cases below + const int modusIP = 0; + const bool useResized = true; + const MathVector center = m_spCutElementHandler->get_center(prtIndex); + +// reset data + m_vRadialAtCo.clear(); + m_vRadialAtCo.resize(this->numCo(), 0.0); + m_vRadialAtIP.clear(); + m_vRadialAtIP.resize(this->numCo(), 0.0); + +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// REMARK: for elements with only ONE outside corner ON the interface, bf.size() = 0! +// => for assembling connections u_fluid -> u_prt, although 'm_vRadialAtCo' is needed! +///////////////////////////////////////////////////////////////////////////////////////////////////////// +// A. set 'm_vRadialAtCo' --> independent of boundary faces! + for (size_t i = 0; i < this->numCo(); ++i) { + if (useResized) { + VecSubtract(m_vRadialAtCo[i], this->corner(i), center); + } else { UG_THROW("in 'update_inner_boundary_radial()': case not implemented anymore!\n");} + + } + +// B. set 'm_vRadialAtIP' --> for boundary faces! + for (size_t i = 0; i < this->m_vBF.size(); ++i) { + interfaceBF bf = this->m_vBF[i]; + + size_t nodeID = bf.node_id(); + if (!useResized) + nodeID = this->corner_orig(nodeID); + + typedef DimFV1FTGeometry > TFVGeom; + TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); + + int ip = (bf.node_id() - 1); + if (ip < 0) + ip = ip + 3; + + const typename TFVGeom::SCVF& scvf = geo.scvf(ip); + const MathVector& SCVFip_Pos = scvf.global_ip(); + + switch (modusIP) { + case 0: // AtIP == AtCo + m_vRadialAtIP[nodeID] = m_vRadialAtCo[nodeID]; + break; + case 1: // AtIP == bf.global_ip() + VecSubtract(m_vRadialAtIP[nodeID], bf.global_ip(), center); + // VecNormalize(m_vRadialAtIP[nodeID], m_vRadialAtIP[nodeID]); + // VecScale(m_vRadialAtIP[nodeID], m_vRadialAtIP[nodeID], radius); + break; + case 2: // AtIP == bf.normal() + UG_THROW("in 'update_inner_boundary_radial()': case not implemented anymore!\n"); + break; + case 3: + VecSubtract(m_vRadialAtIP[nodeID], SCVFip_Pos, center); + // VecNormalize(m_vRadialAtIP[ip], m_vRadialAtIP[ip]); + // VecScale(m_vRadialAtIP[ip], m_vRadialAtIP[ip], VecLength(bf.normal())); + break; + default: + throw(UGError( + "Error in IInterfaceMapper::update_inner_boundary_radial()!")); + } + + } + +} + +template +void InterfaceHandlerLocalParticle:: +update_inner_boundary_radial_for2_StdFV() +{ +// REMARK: not finally tested! + UG_THROW("InterfaceHandlerLocalParticle::update_inner_boundary_radial_for2_StdFV(): not finally tested!!!!\n"); + + const int prtIndex = get_prtIndex(); + +// some check + if (prtIndex == -1) + UG_THROW("InterfaceHandlerLocalParticle::update_inner_boundary_radial_for2_StdFV(): prtIndex not set!\n"); + + const MathVector center1 = m_spCutElementHandler->get_center(0); + const MathVector center2 = m_spCutElementHandler->get_center(1); + + UG_LOG("center1: " << center1 << "\n"); + UG_LOG("center2: " << center2 << "\n"); + +// reset data + m_vRadialAtCo.clear(); + m_vRadialAtCo.resize(this->numCo(), 0.0); + m_vRadialAtIP.clear(); + m_vRadialAtIP.resize(this->numCo(), 0.0); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////// + // REMARK: for elements with only ONE outside corner ON the interface, bf.size() = 0! + // => for assembling connections u_fluid -> u_prt, although 'm_vRadialAtCo' is needed! + ///////////////////////////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////////////////////////// + // A. set 'm_vRadialAtCo' --> independent of boundary faces! + // fill m_vRadialAtCO for center1: + + MathVector RadialIPRef1; + MathVector RadialIPRef2; + RadialIPRef1 = 0.0; + RadialIPRef2 = 0.0; + size_t numOutCo1 = 0; + size_t numOutCo2 = 0; + + if (dim == 2 && this->numCo() != 3) + UG_THROW( + "' in update_inner_boundary_radial_for2_StdFV(): wrong number of corners! -> numCo = " << this->numCo() << "\n"); + + for (size_t i = 0; i < this->numCo(); ++i) { + const int prtIndex = getPrtIndex(i); + + // set 'm_vRadialAtCo' + if (prtIndex == 0) { + VecSubtract(m_vRadialAtCo[i], this->corner(i), center1); + RadialIPRef1 += this->corner(i); + numOutCo1++; + + if (!this->lies_onInterface(i)) + UG_THROW( + "inconsistent in 'update_inner_boundary_radial_for2_StdFV()'!\n"); + } else if (prtIndex == 1) { + VecSubtract(m_vRadialAtCo[i], this->corner(i), center2); + RadialIPRef2 += this->corner(i); + numOutCo2++; + + if (!this->lies_onInterface(i)) + UG_THROW( + "inconsistent in 'update_inner_boundary_radial_for2_StdFV()'!\n"); + } + + } + +// set 'm_vRadialAtIP' + VecScale(RadialIPRef1, RadialIPRef1, 1.0 / numOutCo1); + VecScale(RadialIPRef2, RadialIPRef2, 1.0 / numOutCo2); + UG_LOG("RadialIPRef1 = " << RadialIPRef1 << "\n"); + UG_LOG("RadialIPRef2 = " << RadialIPRef2 << "\n"); + + for (size_t i = 0; i < this->numCo(); ++i) { + const int prtIndex = getPrtIndex(i); + + if (prtIndex == 0) { + VecSubtract(m_vRadialAtIP[i], RadialIPRef1, center1); + } + else if (prtIndex == 1) { + VecSubtract(m_vRadialAtIP[i], RadialIPRef2, center2); + } + + } + +} + +// VORSICHT: update_inner_boundary_radial() wird in fv1FT_geom_impl.h aufgerufen, BEVOR remap_BF() stattfindet! +// => bf.node_id() immer mit interfaceID, nicht OriginalCornerID! +template +void InterfaceHandlerLocalParticle:: +update_inner_boundary_radial_for2() +{ +// REMARK: not finally tested! + UG_THROW("InterfaceHandlerLocalParticle::update_inner_boundary_radial_for2(): not finally tested!!!!\n"); + +// get data: + std::vector > vCornerCoords; + for (size_t i = 0; i < 4; ++i) + vCornerCoords.push_back(this->m_vQuadriCorners_for2[i]); + +// we choose the modusIP = 0 and useResized = true +// --> see implemenation and cases below + const int modusIP = 1; + const bool useResized = true; + + const int prtIndex = get_prtIndex(); + +// some Check + if (prtIndex == -1) + UG_THROW("InterfaceHandlerLocalParticle::update_inner_boundary_radial(): prtIndex not set!\n"); + + if (this->m_vBF.size() != 4) + UG_THROW("in 'update_inner_boundary_radial_for2()': this->m_vBF.size() should be 4, but is " + << this->m_vBF.size() << "\n"); + + const MathVector center1 = m_spCutElementHandler->get_center(0); + const MathVector center2 = m_spCutElementHandler->get_center(1); + + UG_LOG("center1: " << center1 << "\n"); + UG_LOG("center2: " << center2 << "\n"); + +// reset data + m_vRadialAtCo.clear(); + m_vRadialAtCo.resize(4, 0.0); + m_vRadialAtIP.clear(); + m_vRadialAtIP.resize(4, 0.0); + + ///////////////////////////////////////////////////////////////////////////////////////////////////////// + // REMARK: for elements with only ONE outside corner ON the interface, bf.size() = 0! + // => for assembling connections u_fluid -> u_prt, although 'm_vRadialAtCo' is needed! + ///////////////////////////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////////////////////////// + // A. set 'm_vRadialAtCo' --> independent of boundary faces! + // fill m_vRadialAtCO for center1: + for (size_t i = 0; i < 2; ++i) { + if (useResized) + VecSubtract(m_vRadialAtCo[i], vCornerCoords[i], center1); + else + UG_THROW("in 'update_inner_boundary_radial_for2()': not implemented in the for2-case!\n"); + + } + // fill m_vRadial for center2: + for (size_t i = 2; i < 4; ++i) { + if (useResized) + VecSubtract(m_vRadialAtCo[i], vCornerCoords[i], center2); + else + UG_THROW("in 'update_inner_boundary_radial_for2()': not implemented in the for2-case!\n"); + + UG_LOG("-> vCornerCoords[" << i << "] = " << vCornerCoords[i] << "\n"); + UG_LOG("-> m_vRadialAtCo[" << i << "] = " << m_vRadialAtCo[i] << "\n"); + } + + ///////////////////////////////////////////////////////////////////////////////////////////////////////// + // B. set 'm_vRadialAtIP' --> for boundary faces! + // fill m_vRadialAtCO for center1: + for (size_t i = 0; i < 2; ++i) { + interfaceBF bf = this->m_vBF[i]; + + size_t nodeID = bf.node_id(); // ok, since bf.nodeID = 0,1,2,3 + if (!useResized) + UG_THROW("in 'update_inner_boundary_radial_for2()': case '!useResized' not implemented!\n"); + + int ip = (bf.node_id() - 1); + if (ip < 0) + ip = ip + 3; + + switch (modusIP) { + case 0: // AtIP == AtCo + m_vRadialAtIP[nodeID] = m_vRadialAtCo[nodeID]; + break; + case 1: // AtIP == bf.global_ip() + VecSubtract(m_vRadialAtIP[nodeID], bf.global_ip(), center1); + break; + default: + throw(UGError( + "Error in InterfaceHandlerLocalParticle::update_inner_boundary_radial_for2()!")); + } + + } + + // fill m_vRadialAtCO for center2: + for (size_t i = 2; i < 4; ++i) { + interfaceBF bf = this->m_vBF[i]; + + size_t nodeID = bf.node_id(); // ok, since bf.nodeID = 0,1,2,3 + if (!useResized) + UG_THROW("in 'update_inner_boundary_radial_for2()': case '!useResized' not implemented!\n"); + + int ip = (bf.node_id() - 1); + if (ip < 0) + ip = ip + 3; + + switch (modusIP) { + case 0: // AtIP == AtCo + m_vRadialAtIP[nodeID] = m_vRadialAtCo[nodeID]; + break; + case 1: // AtIP == bf.global_ip() + VecSubtract(m_vRadialAtIP[nodeID], bf.global_ip(), center2); + break; + default: + throw(UGError( + "Error in InterfaceHandlerLocalParticle::update_inner_boundary_radial_for2()!")); + } + + } + +} + +template +void InterfaceHandlerLocalParticle:: +update_inner_boundary_radial_StdFV(const MathVector* vCornerCoords) +{ + const int prtIndex = get_prtIndex(); + + if (prtIndex == -1) + UG_THROW("InterfaceHandlerLocalParticle::update_inner_boundary_radial(): prtIndex not set!\n"); + + const MathVector center = m_spCutElementHandler->get_center(prtIndex); + + /* + typedef DimFV1FTGeometry > TFVGeom; + TFVGeom& geo = GeomProvider::get(LFEID(LFEID::LAGRANGE, dim, 1), 1); + */ +// reset data + m_vRadialAtCo.clear(); + m_vRadialAtCo.resize(this->numCo(), 0.0); + m_vRadialAtIP.clear(); + m_vRadialAtIP.resize(this->numCo(), 0.0); + +// Loop the boundary faces to assemble impulse equations + MathVector RadialIPRef; + RadialIPRef = 0.0; + size_t numOutCo = 0; + for (size_t i = 0; i < this->numCo(); ++i) { + // set 'm_vRadialAtCo' + VecSubtract(m_vRadialAtCo[i], this->corner(i), center); + + // set 'm_vRadialAtIP' + /* const typename TFVGeom::SCVF& scvf = geo.scvf(i); + const MathVector& SCVFip_Pos = scvf.global_ip(); + VecSubtract(m_vRadialAtIP[i], SCVFip_Pos, center); + */ + //VecSubtract(m_vRadialAtIP[i], this->corner(i), center); + // compute radialAtIP for current element: + if (this->lies_onInterface(i)) { + RadialIPRef += this->corner(i); + numOutCo++; + } + + } + +// set 'm_vRadialAtIP' + VecScale(RadialIPRef, RadialIPRef, 1.0 / numOutCo); + for (size_t i = 0; i < this->numCo(); ++i) + VecSubtract(m_vRadialAtIP[i], RadialIPRef, center); + +} + +} // end namespace ug + + + +#endif /* INTERFACE_HANDLER_LOCAL_PARTICLE_TOOLS_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/Info File b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/Info File new file mode 100644 index 000000000..f080184fa --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/Info File @@ -0,0 +1,22 @@ +/* Info File for 'InterfaceHandlerDiffusion' class: */ + + +ATTENTION: only implemented and tested for 2d case! + +For the simulation of elliptic problems with discontinuous coefficients, the domain on BOTH sides of the interface in part of the physical domain. Therefore, DOUBLE data needs to be provided locally for each cut element, for each cut part of either domain. + +=> All data structure, which stores local indices (like m_vInterfaceID, m_vRealCornerID) get the distinction via _tri, _quad (for 2d case only!). + +=> For the assembling within the local-to-global mapper, the usual local stiffnes matrix and defect can not be used. Specific data storage is provided by the 'InterfaceHandlerDiffusion' (see new members below). + + +==> Most important new members: + +- LocalMatrix m_locJ_tri; +- LocalMatrix m_locJ_quad; +- LocalVector m_locD_tri; +- LocalVector m_locD_quad; +- LocalVector m_locU_tri; +- LocalVector m_locU_quad; + +---> Local assembling data which gets forwarded to the local-to-global mapper. \ No newline at end of file diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/interface_handler_diffusion.h b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/interface_handler_diffusion.h new file mode 100644 index 000000000..813ad5b5d --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/interface_handler_diffusion.h @@ -0,0 +1,431 @@ +/* + * interface_handler_diffusion.h + * + * Created on: 15.01.2015 + * Author: suze + */ + +#ifndef INTERFACE_HANDLER_LOCAL_DIFFUSION_H_ +#define INTERFACE_HANDLER_LOCAL_DIFFUSION_H_ + + +#include "lib_grid/multi_grid.h" + +#include "../interface_handler_base.h" + + +namespace ug{ + +template +class DimFV1CutGeometry; + +template +class InterfaceHandlerLocalDiffusion : public InterfaceHandlerLocalBase +{ +// typedef InterfaceHandlerLocalBase base_class; + + public: + /// world dimension + static const int dim = TWorldDim; + + /// max number of geometric objects in a dimension + // (most objects in 1 dim, i.e. number of edges, but +1 for 1D) + static const int maxMid = DimFV1CutGeometry >::maxNumSCVF + 1; + + /// used traits + typedef fv1_dim_traits traits; + + /// used boundary face type + typedef typename DimFV1CutGeometry >::BF interfaceBF; + + /// Type of position coordinates + typedef MathVector position_type; + + /// Type of Position Attachment + typedef Attachment position_attachment_type; + + /// Type of Accessor to the Position Data Attachment + typedef Grid::VertexAttachmentAccessor position_accessor_type; + + + InterfaceHandlerLocalDiffusion(SmartPtr > interfaceProvider, + SmartPtr > cutElementHandler); + + virtual ~InterfaceHandlerLocalDiffusion() {} + + ////////////////////////////////////////////////////////////////// + /// virtual methods in 'IInterfaceHandlerLocal' + ////////////////////////////////////////////////////////////////// + + // simple forwarding to the associated 'CutElementHandler' class: + + bool is_onInterfaceVertex(Vertex* vrt, size_t vrtIndex) + { return m_spCutElementHandler->is_onInterfaceVertex(vrt, vrtIndex);} + + bool is_OutsideVertex(Vertex* vrt, size_t vrtIndex) + { return m_spCutElementHandler->is_OutsideVertex(vrt, vrtIndex);} + + bool is_nearInterfaceVertex(Vertex* vrt, size_t vrtIndex) + { return m_spCutElementHandler->is_nearInterfaceVertex(vrt, vrtIndex);} + + bool is_nearInterface(Vertex* vrt) + { return m_spCutElementHandler->is_nearInterface(vrt);} + + ////////////////////////////////////////////////////////////////// + /// virtual methods of 'InterfaceHandlerLocalBase' + ////////////////////////////////////////////////////////////////// + + // forwarding to m_spCutElementHandler: + number get_LSvalue_byPosition(MathVector vrtPos) + { return m_spCutElementHandler->get_LSvalue_byPosition(vrtPos); } + + bool get_intersection_point(MathVector& Intersect, Vertex* vrtOutsideCirc, + Vertex* vrtInsideCirc); + bool get_intersection_point(MathVector& Intersect, Vertex* vrtOutsideCirc, + Vertex* vrtInsideCirc, std::vector& alphaOut); + + + /// recomputes the 'vCornerCoords' of the cut element and derives 'm_roid' + void compute_cut_element_data(GridObject* elem); + + void compute_and_set_prtIndex(GridObject* elem) + { m_spCutElementHandler->compute_and_set_prtIndex(elem); } + + /// central method called by 'compute_cut_element_data()' to compute 'vCornerCoords' + int CollectCorners_FlatTop_2d(GridObject* elem); + + /// helper method within 'CollectCorners_FlatTop_2d' to bring the newly computed + // 'vCornerCoords' in correct order (counter clockwise) + void Resort_RealCornerID(); + + void Collect_Data_Nitsche(GridObject* elem); + + + ////////////////////////////////////////////////////////////////////////////// + /// initialize interface boundary conditions via lua-call + ////////////////////////////////////////////////////////////////////////////// + + void set_source_data_lua(const number interfaceSourceValue) + { m_interfaceSource = interfaceSourceValue; m_luaSource_isSet = true; } + void set_jump_data_lua(const number interfaceJumpValue) + { m_interfaceJump = interfaceJumpValue; m_luaJump_isSet = true; } + void set_jump_grad_data_lua(const MathVector<2>& interfaceJumpGradValue) + { m_interfaceJumpGrad[0] = interfaceJumpGradValue[0]; + m_interfaceJumpGrad[1] = interfaceJumpGradValue[1]; m_luaJumpGrad_isSet = true; } + void set_diffusion_coeff_data_lua(const MathVector<2>& diffusionCoeffs) + { m_diffusionCoeff[0] = diffusionCoeffs[0]; m_diffusionCoeff[1] = diffusionCoeffs[1]; + m_luaDiffusion_isSet = true; } + + + ////////////////////////////////////////////////////////// + /// getter methods + ////////////////////////////////////////////////////////// + + + /// access to m_vBF (needed during 'FV1CutGeom::update_inner_boundary_faces()') + std::vector& get_boundary_faces() { return m_vBF; } + /// called during 'update()'-method of Fv1CutGeom + void clear_boundary_faces() { m_vBF.clear(); } + + const LocalIndices& get_local_indices() const { return m_ind; } + + MathVector get_center(int prtIndex){ return m_spCutElementHandler->get_center(prtIndex);} + + // methods for writing and getting GLOBAL data of interface nodes + size_t get_or_insert_vertex(const MathVector& vrtPos); + size_t get_or_insert_vertex(Vertex* vrt); + bool find_vrtPos(const MathVector& vrtPos); + + size_t get_index_for_global_index_Nitsche(const size_t i); + size_t get_global_index_Nitsche(const size_t i) { return m_verticesGlobalIndex[i]; } + const size_t get_num_NitscheDoFs() { return m_MapInserted_Nitsche.size(); } + + // used for Nitsche + void set_Nitsche(bool bNitsche){ m_bNitsche = bNitsche;} + bool get_Nitsche(){ return m_bNitsche;} + + // ---> used during 'diffusion_interface/diffusion_interface.h:initialize_interface_Nitsche()': + size_t get_or_insert_indexPair_Nitsche(const size_t global_index); + + + //////////////////////////////////////////////////////////////////////////////////// + /// methods called by the Elem Disc 'ConvectionDiffusionFV1_cutElem' + //////////////////////////////////////////////////////////////////////////////////// + + ///////////////////////////////////////////////////////////////////////////////////////////// + // (A) 'integral'-methods: for the computation of the l2-error within + // 'ConvectionDiffusionFV1_cutElem::add_l2error_A_elem()' + + void L2Error_add(const number value) { m_L2Error += value; } + void L2Error_init(){ m_L2Error = 0.0;} + number get_L2Error(){ return m_L2Error;} + + ///////////////////////////////////////////////////////////////////////////////////////////// + /// (B) further methods + + void resize_local_data(LocalVector locU); + + const bool get_boolian_for_diffusion(); + + void set_DoF_tag(const bool bFactor2_for_DoFIndex, const ReferenceObjectID roid) + { if ( roid == ROID_TRIANGLE ) {m_shift_DoFIndex_tri = bFactor2_for_DoFIndex; return;} + else if ( roid == ROID_QUADRILATERAL ) {m_shift_DoFIndex_quad = bFactor2_for_DoFIndex; return;} + else {UG_THROW("in InterfaceHandlerLocalDiffusion::set_DoF_tag_tri(): invalid roid!\n");} + } + + void set_bScaleDoFs(bool bScaleDoF) { m_scaleDoFs = bScaleDoF; } + bool get_bScaleDoFs() { return m_scaleDoFs; } + + const bool get_bNearInterface() const {return m_bNearInterface;} + void set_bNearInterface(bool bNearInterface) { m_bNearInterface = bNearInterface;} + + ///////////////////////////////////////////////////////////////////////////////////////////// + // (C) access methods for assemgling of the local defect and jacobian for + // the elem Disc 'ConvectionDiffusionFV1_cutElem': + // --> during call of 'add_jac_A_elem()' and 'add_def_A_elem()' + + void reset_defect_on_interface(LocalVector& locD, const size_t size); + void reset_jacobian_on_interface(LocalMatrix& locJ, const size_t size); + + void set_jacobian(const LocalMatrix locJ, const ReferenceObjectID roid) + { if ( roid == ROID_TRIANGLE ) m_locJ_tri = locJ; + else if ( roid == ROID_QUADRILATERAL ) m_locJ_quad = locJ; + else {UG_THROW("in InterfaceHandlerLocalDiffusion::set_jacobian(): invalid roid!\n");} + } + + void set_defect(const LocalVector locD, const ReferenceObjectID roid) + { if ( roid == ROID_TRIANGLE ) m_locD_tri = locD; + else if ( roid == ROID_QUADRILATERAL ) m_locD_quad = locD; + else {UG_THROW("in InterfaceHandlerLocalDiffusion::set_defect(): invalid roid!\n");} + } + + + const size_t get_numVerticesPos() const { return m_verticesPos.size(); } + const MathVector get_VerticesPos(size_t index) const { return m_verticesPos[index]; } + const double get_sol(size_t index) const { return m_verticesValue[index]; } + const double get_sol(size_t index, size_t fct) const { return m_verticesValue[index]; } + + // also called by class 'DiffusionInterfaceMapper' + LocalMatrix& get_local_jacobian(const ReferenceObjectID roid) + { if ( roid == ROID_TRIANGLE ) return m_locJ_tri; + else if ( roid == ROID_QUADRILATERAL ) return m_locJ_quad; + else {UG_THROW("in InterfaceHandlerLocalDiffusion::get_local_jacobian(): invalid roid!\n");} + } + + LocalVector& get_local_defect(const ReferenceObjectID roid) + { if ( roid == ROID_TRIANGLE ) return m_locD_tri; + else if ( roid == ROID_QUADRILATERAL ) return m_locD_quad; + else {UG_THROW("in InterfaceHandlerLocalDiffusion::get_local_defect(): invalid roid!\n");} + } + + LocalVector& get_local_solution(const ReferenceObjectID roid) + { if ( roid == ROID_TRIANGLE ) return m_locU_tri; + else if ( roid == ROID_QUADRILATERAL ) return m_locU_quad; + else {UG_THROW("in InterfaceHandlerLocalDiffusion::get_local_solution(): invalid roid!\n");} + } + + + ///////////////////////////////////////////////////////////////////////////////////////////// + // (D) access methods for local assembling of the boundary conditions on the + // immersed interface into the defect and jacobian for the elem Disc + // 'ConvectionDiffusionFV1_cutElem' + // --> during call of 'add_jac_A_elem()' and 'add_def_A_elem()' + + // diffusion can only be set as values, with constant diff coefficient at each side of the interface. + // no _impl() methods provided for analytic lua-functions + number get_diffusion(); + number get_diffusion(const bool bElementIsOutside); + + double get_jump(const MathVector position); + double get_jump_impl(const MathVector position); + + double get_jump_grad(const MathVector position); + double get_jump_grad_impl(const MathVector position); + + double get_source(const MathVector position); + double get_source_impl(const MathVector position); + + // setter methods (called by ConvectionDiffusionFV1_cutElem::get_local_data() ) + void set_local_sol(LocalVector& solU, const size_t size, const LocalVector& lvec, + const int orientation); + + void set_jump_values (LocalVector& jumpOut, LocalIndices ind, const size_t size); + void set_jump_grad_values(LocalVector& jumpGradOut, LocalIndices ind, const size_t size); + void set_source(const std::vector sourceIm, LocalVector& sourceOut, LocalIndices ind, + const size_t size, const bool bElementIsCut); + + bool lies_onInterface_tri(const size_t newID); + bool lies_onInterface_quad(const size_t newID); + bool lies_onInterface_size(const size_t newID, size_t size); + + + ////////////////////////////////////////////////////////////////////////////// + /// methods called by class 'DiffusionInterfaceMapper' + ////////////////////////////////////////////////////////////////////////////// + + const size_t get_index_shift_tri() const { return m_shift_DoFIndex_tri; } + const size_t get_index_shift_quad() const { return m_shift_DoFIndex_quad; } + + + // LOCAL access to 'VertexModus' via 'm_vvVertexMode' data in 'CutElementHandler' class + bool check_vertex_modus(VertexModus vrtModus, size_t vrtIndex, const int interfaceOrientation) + { return m_spCutElementHandler->check_vertex_modus(vrtModus, vrtIndex, interfaceOrientation);} + + // writes solution of the interface nodes (i.e. of the new DoFs) from + // the global vector 'vec' into this->m_verticesValue-array: + void set_interface_values(const std::vector verticesValues); + + + ////////////////////////////////////////////////////////////////////////////// + /// access to entries of the GLOBAL index of interface nodes 'm_vRealCornerID' + ////////////////////////////////////////////////////////////////////////////// + + // get the 'real index': + // case1: node lies on interface => returns the entry location within + // 'InterfaceHandlerDiffusion::m_MapNearVertices' + // case2: node lies on an original mesh node: => returns the usual, + // local index of vertex + + /// called by own class 'InterfaceHandlerLocalDiffusion' + const size_t real_index(size_t i) const { return m_vRealCornerID[i]; } + const size_t real_index_size(size_t i, const size_t size) const + { if ( size == 3 ) return m_vRealCornerID_tri[i]; + else if ( size == 4 ) return m_vRealCornerID_quad[i]; + else UG_THROW("in 'real_index_size()': wrong size (should be 3 or 4!): " << size << "n"); + } + + // called by class 'DiffusionInterfaceMapper': + const size_t real_index_tri(size_t i) const { return m_vRealCornerID_tri[i]; } + const size_t real_index_quad(size_t i) const { return m_vRealCornerID_quad[i]; } + + + ////////////////////////////////////////////////////////// + /// output + ////////////////////////////////////////////////////////// + + void print_Nitsche_Data(); + void print_CutElementData(); + + ////////////////////////////////////////////////////////// + /// acces methods for Nitsche + ////////////////////////////////////////////////////////// + + number vAlpha(size_t i, size_t j) { return m_vAlpha[i][j]; } + MathVector vIntersectionPnts(size_t i) { return m_vIntersectionPnts[i]; } + MathMatrix vShapeValues() { return m_vShapeValues; } + MathVector NormalToFace() { return m_NormalToFace; } + number Gamma() { return m_Gamma; } + number Area() { return m_Area; } + number AreaOrig() { return m_AreaOrig; } + number AreaScale() { return m_AreaScale; } + number IntegralGamma(size_t i) { return m_vIntegralGamma[i]; } + + + ////////////////////////////////////////////////////////////////////////////// + /// class member + ////////////////////////////////////////////////////////////////////////////// + + // m_vBF stores the boundary faces of the immersed boundary; + // --> updated during FV1CutGeom::update_inner_boundary_faces() + std::vector m_vBF; + + // storage of new vertices at the immersed interface + std::map, size_t> m_MapInserted; // + std::vector > m_verticesPos; + std::vector m_verticesValue; + + // RealCornerID: for access do solution via DoFRef + // 2 cases: (1) corner lies on interface or (2) corner lies on original grid node + // case1: contains the entry counter of the node within + // 'InterfaceHandlerDiffusion::m_MapNearVertices' (usually > 4) + // case2:contains the usual, 'local' index of vertex + std::vector m_vRealCornerID; + std::vector m_vRealCornerID_tri; + std::vector m_vRealCornerID_quad; + + // m_vInterfaceID_tri/_quad := LOCAL index of interface nodes (< 4) + std::vector m_vInterfaceID_tri; + std::vector m_vInterfaceID_quad; + + /// size of local algebra for cut element: 'm_numFct' x 'm_numCo' + size_t m_numFct; + /// number of corners of cut element + size_t m_numCo; + + /// new local algebra for resized cut element + LocalIndices m_ind; + + // local data for assembling on element being cut into triangle and quadrilateral: + LocalMatrix m_locJ_tri; + LocalMatrix m_locJ_quad; + LocalVector m_locD_tri; + LocalVector m_locD_quad; + LocalVector m_locU_tri; + LocalVector m_locU_quad; + + bool m_scaleDoFs; // if m_scaleDoFs = true: 2 new DoFs will be placed for each interface node (for jump in value) + number m_L2Error; + bool m_bNearInterface; + + // scale factor for access to DoFIndex on triangle or quadri as cut element + // --> for call during 'add_local_def/jac_to_global_interface()': + bool m_shift_DoFIndex_tri; + bool m_shift_DoFIndex_quad; + + /////////////////////////////////////////////////////////////// + /// data for assembling interface boundary condition + + // boolians for boundary condition data: + // if true: constant values are given via lua-call + // if false: position-dependent values are given via inline-function + bool m_luaSource_isSet; + bool m_luaJump_isSet; + bool m_luaJumpGrad_isSet; + bool m_luaDiffusion_isSet; + + // if boolians above are true: constant values are given via lua-call and stored here + number m_interfaceSource; + number m_interfaceJump; + MathVector<2> m_interfaceJumpGrad; + MathVector<2> m_diffusionCoeff; + + /////////////////////////////////////////////////////////////// + /// data for Nitsche -> 'Collect_Data_Nitsche()': + + bool m_bNitsche; + std::map m_MapInserted_Nitsche; + std::vector > m_vAlpha; + std::vector > m_vIntersectionPnts; + MathMatrix m_vShapeValues; // dim+1 = number of vertices for simplicial mesh! + MathVector m_NormalToFace; + number m_Gamma; + MathVector m_insidePnt; + number m_Area; + number m_AreaOrig; + number m_AreaScale; + std::vector m_vIntegralGamma; + + // filled during 'immersed_interface/interface_handler_local_base_tools.h: get_or_insert_indexPair_Nitsche()' + // AND get_or_insert_indexPair_Nitsche() called during 'diffusion_interface/diffusion_interface.h:initialize_interface_Nitsche()' + // and used for local-to-global mapper + std::vector m_verticesGlobalIndex; + + /////////////////////////////////////////////////////////////// + /// essential members for further acces + + /// contains radius, center and orientation of all given particles + SmartPtr > m_spInterfaceProvider; + + /// computes and contains 'ElementModus', 'VertexModus' and handles access + SmartPtr > m_spCutElementHandler; + +}; + + +}// end namespace ug + + +#include "interface_handler_diffusion_tools.h" +#include "interface_handler_diffusion_impl.h" + +#endif /* INTERFACE_HANDLER_LOCAL_DIFFUSION_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/interface_handler_diffusion_impl.h b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/interface_handler_diffusion_impl.h new file mode 100644 index 000000000..b2caf409c --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/interface_handler_diffusion_impl.h @@ -0,0 +1,597 @@ +/* + * interface_handler_local_impl.h + * + * Created on: 19.01.2015 + * Author: suze + */ + +#ifndef INTERFACE_HANDLER_LOCAL_DIFFUSION_IMPL_H_ +#define INTERFACE_HANDLER_LOCAL_DIFFUSION_IMPL_H_ + + +#include "interface_handler_diffusion_user_data.h" + + +namespace ug{ + + +/////////////////////////////////////////////////////////////// +/// methods for class 'IInterfaceHandlerLocal' +/////////////////////////////////////////////////////////////// + + + +/////////////////////////////////////////////////////////////// +/// methods for class 'InterfaceHandlerLocalDiffusion' +/////////////////////////////////////////////////////////////// + +/////////////////////////////////////////////////////////////// +// Constructor +/////////////////////////////////////////////////////////////// +template +InterfaceHandlerLocalDiffusion:: +InterfaceHandlerLocalDiffusion(SmartPtr > interfaceProvider, + SmartPtr > cutElementHandler) : + InterfaceHandlerLocalBase(cutElementHandler), + m_numFct(0), + m_numCo(0), + m_scaleDoFs(false), + m_L2Error(0.0), + m_bNearInterface(false), + m_shift_DoFIndex_tri(false), + m_shift_DoFIndex_quad(false), + m_luaSource_isSet(false), + m_luaJump_isSet(false), + m_luaJumpGrad_isSet(false), + m_luaDiffusion_isSet(false), + m_interfaceSource(0.0), + m_interfaceJump(0.0), + m_interfaceJumpGrad(0.0, 0.0), + m_diffusionCoeff(0.0, 0.0), + m_bNitsche(false), + m_Gamma(0.0), + m_insidePnt(0.0), + m_Area(0.0), + m_AreaOrig(0.0), + m_AreaScale(0.0), + m_spInterfaceProvider(interfaceProvider), + m_spCutElementHandler(cutElementHandler) +{ + m_vBF.clear(); + m_MapInserted.clear(); + m_verticesPos.clear(); + m_verticesValue.clear(); + m_vRealCornerID.clear(); + m_vRealCornerID_tri.clear(); + m_vRealCornerID_quad.clear(); + m_vInterfaceID_tri.clear(); + m_vInterfaceID_quad.clear(); + + m_MapInserted_Nitsche.clear(); + m_vAlpha.clear(); + m_vIntersectionPnts.clear(); + m_verticesGlobalIndex.clear(); +} +////////////////////////////////////////////////////////////////// +/// virtual methods in 'InterfaceHandlerLocalBase' +////////////////////////////////////////////////////////////////// + +template +bool InterfaceHandlerLocalDiffusion:: +get_intersection_point(MathVector& Intersect, Vertex* vrtOutsideCirc, Vertex* vrtInsideCirc) +{ + const int orientation = this->get_orientation(); + const int prtIndex = m_spCutElementHandler->get_prtIndex(); + + if ( prtIndex == -1 ) UG_THROW("'get_intersection_point()': value of prtIndex not valid!\n"); + + const MathVector& vrtPosOut = this->m_aaPos[vrtOutsideCirc]; + const MathVector& vrtPosIn = this->m_aaPos[vrtInsideCirc]; + + if ( orientation == 1 ) + return this->m_spInterfaceProvider->get_intersection_point(Intersect, vrtPosOut, vrtPosIn, prtIndex); +// inverse order of 'vrtPosOut' and 'vrtPosIn' for call of 'get_intersection_point()' +// to avoid error for alpha < 0: + else if ( orientation == -1 ) + return this->m_spInterfaceProvider->get_intersection_point(Intersect, vrtPosIn, vrtPosOut, prtIndex); + else + UG_THROW("in InterfaceHandlerLocalDiffusion::get_intersection_point(): m_orientationInterface not set!\n"); +} + +template +bool InterfaceHandlerLocalDiffusion:: +get_intersection_point(MathVector& Intersect, Vertex* vrtOutsideCirc, Vertex* vrtInsideCirc, std::vector& alphaOut) +{ + const int orientation = this->get_orientation(); + const int prtIndex = m_spCutElementHandler->get_prtIndex(); + + if ( prtIndex == -1 ) UG_THROW("'get_intersection_point()': value of prtIndex not valid!\n"); + + const MathVector& vrtPosOut = this->m_aaPos[vrtOutsideCirc]; + const MathVector& vrtPosIn = this->m_aaPos[vrtInsideCirc]; + + if ( orientation == 1 ) + return this->m_spInterfaceProvider->get_intersection_point(Intersect, vrtPosOut, vrtPosIn, prtIndex, alphaOut); +// inverse order of 'vrtPosOut' and 'vrtPosIn' for call of 'get_intersection_point()' +// to avoid error for alpha < 0: + else if ( orientation == -1 ) + return this->m_spInterfaceProvider->get_intersection_point(Intersect, vrtPosIn, vrtPosOut, prtIndex, alphaOut); + else + UG_THROW("in InterfaceHandlerLocalDiffusion::get_intersection_point(): m_orientationInterface not set!\n"); +} + +/////////////////////////////////////////////////////////////// +// new methods for Diffusion +/////////////////////////////////////////////////////////////// + + +template +void InterfaceHandlerLocalDiffusion:: +resize_local_data(LocalVector locU) +{ + LocalIndices ind = locU.get_indices(); + +// resize for cut triangle + ind.resize_dof(0, 3); + m_locU_tri.resize(ind); + m_locD_tri.resize(ind); + m_locJ_tri.resize(ind); + +// if node is near interface: triangle is cut into 2 triangles: + size_t local_dimension = 4; + if ( get_bNearInterface() ) + local_dimension = 3; + +// resize for cut quadrilateral + ind.resize_dof(0, local_dimension); + m_locU_quad.resize(ind); + m_locD_quad.resize(ind); + m_locJ_quad.resize(ind); + + return; +} + +template +void InterfaceHandlerLocalDiffusion:: +set_interface_values(const std::vector verticesValues) +{ + this->m_verticesValue.clear(); + + for (size_t i = 0; i < verticesValues.size(); ++i) + this->m_verticesValue.push_back(verticesValues[i]); + + +// through error: + if ( this->m_verticesValue.size() != verticesValues.size() ) + { + UG_LOG("m_verticesValue.size(): " << this->m_verticesValue.size() << "\n"); + UG_LOG("verticesValues.size(): " << verticesValues.size() << "\n"); + UG_THROW("in InterfaceHandlerLocalDiffusion::set_interface_values: wrong size of m_verticesValue!\n"); + } + +} + +template +void InterfaceHandlerLocalDiffusion:: +reset_defect_on_interface(LocalVector& locD, const size_t size) +{ + if ( size > locD.num_all_dof(0) ) + { + UG_LOG("in 'reset_defect_on_interface()': size = " << size << ", locD.size = " << locD.num_all_dof(0) << "\n"); + UG_THROW("in 'reset_defect_on_interface()': size = " << size << ", locD.size = " << locD.num_all_dof(0) << " => claimed size is NOT equal to size of solution vector!\n"); + } +// loop and set solution in 'solU_tri': + for (size_t dof = 0; dof < locD.num_all_dof(0); ++dof) + { + // if dof_real is index of m_vertex: get solution from class: + if ( this->lies_onInterface_size(dof, size) ) + locD.value(0, dof) = 0.0; + } +} + +template +void InterfaceHandlerLocalDiffusion:: +reset_jacobian_on_interface(LocalMatrix& locJ, const size_t size) +{ + + if ( size > locJ.num_all_row_dof(0) ) + { + UG_LOG("in 'reset_jacobian_on_interface()': size = " << size << ", locJ.size = " << locJ.num_all_row_dof(0) << "\n"); + UG_THROW("in 'reset_jacobian_on_interface()': size = " << size << ", locJ.size = " << locJ.num_all_row_dof(0) << " => claimed size is NOT equal to size of solution vector!\n"); + } +// loop and set solution in 'solU_tri': + for (size_t dof1 = 0; dof1 < locJ.num_all_row_dof(0); ++dof1) + { + if ( this->lies_onInterface_size(dof1, size) ) + { + // erase all col-values of chosen row dof1: + for (size_t dof2 = 0; dof2 < locJ.num_all_col_dof(0); ++dof2) + locJ.value(0, dof1, 0, dof2) = 0.0; + } + + } + +} + +template +const bool InterfaceHandlerLocalDiffusion:: +get_boolian_for_diffusion() +{ + if( this->elementModus() == OUTSIDE_DOM) + { + return true; + } + else if( this->elementModus() == INSIDE_DOM) + { + return false; + } + else if( this->elementModus() == CUT_BY_INTERFACE) + { + return false; + } + else + { + UG_THROW("in InterfaceHandlerLocalDiffusion:get_boolian_for_diffusion: no valid boolian found!\n"); + return false; + } + + return false; +} + +/////////////////////////////////////////////////////////////// +/// hard coded boundary conditions +/////////////////////////////////////////////////////////////// + +template +inline double get_jump_value_ex6(const MathVector position, const int orientation) +{ + if ( orientation == 1) + return 0.0; + + return exp(position[0])*cos(position[1]); +} + +template +inline double get_jump_grad_value_ex6(const MathVector position, const int orientation) +{ + if ( orientation == -1) + return 0.0; + + double x = position[0]; + double y = position[1]; + + return 2.0*exp(x)*(y*sin(y)-x*cos(y)); +} + + +template +inline double get_source_kappa(const MathVector position, const MathVector center, const int orientation) +{ + + if ( orientation == 1) + return 16.0*16.0; + + if ( orientation != -1) + UG_THROW("wrong orientation!\n"); + + double dist_x = position[0] - center[0]; + double dist_y = position[1] - center[1]; + double dist = sqrt(dist_x*dist_x+dist_y*dist_y); + + return 200*16*dist*dist; + + +} + +/////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////// + +// _impl()-methods used by user to specify the function +// depending on position + +template +double InterfaceHandlerLocalDiffusion:: +get_jump_impl(const MathVector position) +{ +// provide class member data + const int orientation = this->get_orientation(); + +// call inline function: + return get_jump_value_ex6(position, orientation); + +} + +template +double InterfaceHandlerLocalDiffusion:: +get_jump_grad_impl(const MathVector position) +{ +// provide class member data + const int orientation = this->get_orientation(); + +// call inline function: + return get_jump_grad_value_ex6(position, orientation); + } + +template +double InterfaceHandlerLocalDiffusion:: +get_source_impl(const MathVector position) +{ +// provide class member data + const MathVector center = get_center(0); + const int orientation = this->get_orientation(); + +// call inline function: + return get_source_kappa(position, center, orientation); +} + + +// methods calling the flag to decide whether constant lua user data is +// appplied of position-dependent inline c++ funtion _impl() (see above) + +template +double InterfaceHandlerLocalDiffusion:: +get_jump(const MathVector position) +{ + number jump_value = 0.0; + + if (m_luaJump_isSet) + { + jump_value = m_interfaceJump; + } + else + // if the boundary conditions are NOT given by lua call, an own 'inline' implementation is needed: + jump_value = get_jump_impl(position); + + return jump_value; +} + + +template +double InterfaceHandlerLocalDiffusion:: +get_jump_grad(const MathVector position) +{ + number jump_grad_value = 0.0; + + if (m_luaJumpGrad_isSet) + { + if ( this->get_orientation() == 1 ) + jump_grad_value = m_interfaceJumpGrad[0]; + else + jump_grad_value = m_interfaceJumpGrad[1]; + } + else + { + // if the boundary conditions are NOT given by lua call, an own 'inline' implementation is needed: + jump_grad_value = get_jump_grad_impl(position); + } + + + return jump_grad_value; +} + + +template +double InterfaceHandlerLocalDiffusion:: +get_source(const MathVector position) +{ + number source_value = 0.0; + + if ( m_luaSource_isSet) + source_value = m_interfaceSource; + else + { + // if the boundary conditions are NOT given by lua call, an own 'inline' implementation is needed: + source_value = get_source_impl(position); + } + + return source_value; +} + +// the diffusion only has the option for constant values + +template +number InterfaceHandlerLocalDiffusion:: +get_diffusion() +{ + const int orientation = this->get_orientation(); + +// orientation == 1 corresponds to OUTSIDE of the circle (if the interface is a circle) + if ( orientation == 1 ) + return m_diffusionCoeff[0]; + + return m_diffusionCoeff[1]; + +} + +template +number InterfaceHandlerLocalDiffusion:: +get_diffusion(const bool bElementIsOutside) +{ +// bElementIsOutside corresponds to INSIDE of the circle ( if the interface is a circle) + if ( bElementIsOutside ) + return m_diffusionCoeff[1]; + + return m_diffusionCoeff[0]; + +} + +/////////////////////////////////////////////////////////////// +/// setter functions called during elem disc +/// 'ConvectionDiffusionFV1_cutElem' to set bndCond +/////////////////////////////////////////////////////////////// + +template +void InterfaceHandlerLocalDiffusion:: +set_source(const std::vector sourceIm, LocalVector& sourceOut, LocalIndices ind, + const size_t size, const bool bElementIsCut) +{ + ind.resize_dof(0, size); + sourceOut.resize(ind); + +// loop and write solution to 'sourceOut': + for (size_t dof = 0; dof < sourceOut.num_all_dof(0); ++dof) + { + if ( !bElementIsCut ) + { + sourceOut.value(0, dof) = sourceIm[dof]; + } + // if dof_real is index of m_vertex: get values from InterfaceHandler: + else if ( this->lies_onInterface_size(dof, size) ) + { + size_t dof_real = this->real_index_size(dof, size); + sourceOut.value(0, dof) = get_source(this->get_VerticesPos(dof_real)); + } + else + { + size_t dof_orig = this->corner_orig(dof); + sourceOut.value(0, dof) = sourceIm[dof_orig]; + } + + } + + return; +} + + +template +void InterfaceHandlerLocalDiffusion:: +set_jump_values(LocalVector& jumpOut, LocalIndices ind, const size_t size) +{ + ind.resize_dof(0, size); + jumpOut.resize(ind); + +// loop and write values to 'jumpOut': + for (size_t dof = 0; dof < jumpOut.num_all_dof(0); ++dof) + { + + // if dof_real is index of m_vertex: get solution from class: + if ( this->lies_onInterface_size(dof, size) ) + { + size_t dof_real = this->real_index_size(dof, size); + jumpOut.value(0, dof) = get_jump(this->get_VerticesPos(dof_real)); + } + else + { + jumpOut.value(0, dof) = 0.0; + } + } + + return; +} + + + +template +void InterfaceHandlerLocalDiffusion:: +set_jump_grad_values(LocalVector& jumpGradOut, LocalIndices ind, const size_t size) +{ + ind.resize_dof(0, size); + jumpGradOut.resize(ind); + + // loop and set solution in 'solU_tri': + for (size_t dof = 0; dof < jumpGradOut.num_all_dof(0); ++dof) + { + + // if dof_real is index of m_vertex: get solution from class: + if ( this->lies_onInterface_size(dof, size) ) + { + size_t dof_real = this->real_index_size(dof, size); + jumpGradOut.value(0, dof) = get_jump_grad(this->get_VerticesPos(dof_real)); + } + else + { + jumpGradOut.value(0, dof) = 0.0; + } + } + + return; + +} + +template +void InterfaceHandlerLocalDiffusion:: +set_local_sol(LocalVector& solU, const size_t size, const LocalVector& lvec, const int orientation) +{ + if ( size > solU.num_all_dof(0) ) + { + UG_LOG("in 'set_local_sol()': size = " << size << ", solU.size = " << solU.num_all_dof(0) << "\n"); + UG_THROW("in 'set_local_sol()': size = " << size << ", solU.size = " << solU.num_all_dof(0) << " => claimed size is NOT equal to size of solution vector!\n"); + } +// loop and set solution in 'solU': + for (size_t dof = 0; dof < solU.num_all_dof(0); ++dof) + { + size_t dof_real = this->real_index_size(dof, size); + + // if dof_real is index of m_vertex: get solution from the 'm_verticesValue'-array: + if ( this->lies_onInterface_size(dof, size) ) + { + solU.value(0, dof) = this->get_sol(dof_real); + ////////////////////////////////////////////// + // add jump value in case of element, lying on \Omega^-: + ////////////////////////////////////////////// + // solU.value(0, dof) += get_jump_value_ex3(this->get_VerticesPos(dof_real)); + } + else + { + solU.value(0, dof) = lvec.value(0,dof_real); + } + } +} + + + +/////////////////////////////////////////////////////////////// +// new methods from base class +/////////////////////////////////////////////////////////////// + +// see mod_elem_flat_top() of flat_top.h +template +void InterfaceHandlerLocalDiffusion:: +compute_cut_element_data(GridObject* elem) +{ +// get new element corners and according element type + if ( this->StdFV_assembling() ) // Version an Stelle von 'm_bUsualAss = true' + { + this->CollectCorners_StdFV(elem); + + if ( dim == 2 ) this->set_roid_2d(); + if ( dim == 3 ) this->set_roid_3d(); + } + else + { + if ( dim == 2 ) + { + if ( get_Nitsche() ) + { Collect_Data_Nitsche(elem); this->set_roid_2d(); } + else + { CollectCorners_FlatTop_2d(elem); this->set_roid_2d(); } + } + + if ( dim == 3 ) { this->CollectCorners_FlatTop_3d(elem); this->set_roid_3d(); } + } + + // some checks: + if ( this->m_vCornerCoords.size() == 0 ) + UG_THROW("m_vCornerCoords.size() = " << this->m_vCornerCoords.size() << "not possible!\n"); + + if ( dim == 2 ) + if ( elem->reference_object_id() != ROID_TRIANGLE ) + UG_THROW("Discretisation only coded for triangular elements!\n"); + + if ( dim == 3 ) + if ( elem->reference_object_id() != ROID_TETRAHEDRON ) + UG_THROW("Discretisation only coded for tetrahedral elements!\n"); + +// output computed data to file + if ( this->print_cutElment_data() ) + print_CutElementData(); + + + +} + +} // end namespace ug + + + +#endif /* INTERFACE_HANDLER_LOCAL_DIFFUSION_IMPL_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/interface_handler_diffusion_tools.h b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/interface_handler_diffusion_tools.h new file mode 100644 index 000000000..59305e685 --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/interface_handler_diffusion_tools.h @@ -0,0 +1,667 @@ +/* + * interface_handler_local_tools.h + * + * Created on: 19.01.2015 + * Author: suze + */ + +#ifndef INTERFACE_HANDLER_LOCAL_DIFFUSION_TOOLS_H_ +#define INTERFACE_HANDLER_LOCAL_DIFFUSION_TOOLS_H_ + +namespace ug{ + +//////////////////////////////////////////////////////////////////////////////// +// FlatTopBase methods - ROID/CollectCorners... +//////////////////////////////////////////////////////////////////////////////// + +// used for local_to_global mapping + +template +bool InterfaceHandlerLocalDiffusion:: +lies_onInterface_tri(const size_t newID) +{ + for ( size_t i = 0; i < m_vInterfaceID_tri.size(); ++i) + if ( m_vInterfaceID_tri[i] == newID ) + return true; + + return false; +} + +template +bool InterfaceHandlerLocalDiffusion:: +lies_onInterface_quad(const size_t newID) +{ + for ( size_t i = 0; i < m_vInterfaceID_quad.size(); ++i) + if ( m_vInterfaceID_quad[i] == newID ) + return true; + + return false; +} + +template +bool InterfaceHandlerLocalDiffusion:: +lies_onInterface_size(const size_t newID, size_t size) +{ + if ( size == 3 ) + return lies_onInterface_tri(newID); + else if ( size == 4 ) + return lies_onInterface_quad(newID); + else UG_THROW("in 'lies_onInterface_sized()': invalid size (shold be 3 or 4!):" << size << "\n"); + +} + + +// used during 'diffusion_interface/diffusion_interface.h:initialize_interface_Nitsche()': +template +size_t InterfaceHandlerLocalDiffusion:: +get_or_insert_indexPair_Nitsche(const size_t global_index) +{ + + std::pair::iterator,bool> ret; + ret = m_MapInserted_Nitsche.insert ( std::pair(global_index, m_MapInserted_Nitsche.size()) ); + + if (ret.second==false) { + //UG_LOG("element already existed with a value of " << ret.first->second << "\n"); + } + else{ + m_verticesGlobalIndex.push_back(global_index); + UG_LOG("global_index: " << global_index << "\n"); + + UG_LOG("ret.first->first: " << ret.first->first << "\n"); + UG_LOG("ret.first->second: " << ret.first->second << "\n"); + } + + return ret.first->second; + +} + +template +size_t InterfaceHandlerLocalDiffusion:: +get_index_for_global_index_Nitsche(const size_t global_index) +{ + for ( size_t i = 0; i < m_verticesGlobalIndex.size(); ++i) + if ( m_verticesGlobalIndex[i] == global_index ) + return i; + + UG_THROW("in 'global_index_of_interface_DoF_Nitsche': no index in m_verticesGlobalIndex-vector found for global_index = " << global_index << "\n"); +} + +template +size_t InterfaceHandlerLocalDiffusion:: +get_or_insert_vertex(Vertex* vrt) +{ + MathVector vrtPos = this->m_aaPos[vrt]; + + // near interface vertices are remapped onto grid points => NO new DoF! => No addint into list! + if (is_nearInterface(vrt) ) + return -1; + + get_or_insert_vertex(vrtPos); + +} + +template +bool InterfaceHandlerLocalDiffusion:: +find_vrtPos(const MathVector& vrtPos) +{ + typename std::map,size_t>::iterator it; + it = m_MapInserted.find(vrtPos); + + // if ret.second == false, then vrtPos allready exists in n_MapInserted + if (it != m_MapInserted.end()) + return true; + + return false; + +} + +template +size_t InterfaceHandlerLocalDiffusion:: +get_or_insert_vertex(const MathVector& vrtPos) +{ + std::pair,size_t>::iterator,bool> ret; + ret = m_MapInserted.insert ( std::pair,size_t>(vrtPos,m_MapInserted.size()) ); + + if (ret.second==false) { + //UG_LOG("element already existed with a value of " << ret.first->second << "\n"); + } + else{ + m_verticesPos.push_back(vrtPos); + } + + return ret.first->second; +} + +template +void InterfaceHandlerLocalDiffusion:: +Resort_RealCornerID() +{ + m_vRealCornerID_quad.clear(); + + for ( size_t i = 0; i < this->m_vOriginalCornerID.size(); ++i ) + { + size_t origID = this->m_vOriginalCornerID[i]; + if ( !this->lies_onInterface(i) ) + m_vRealCornerID_quad.push_back(origID); + else if ( !find_vrtPos(this->m_vCornerCoords[i]) ) + m_vRealCornerID_quad.push_back(origID); + else + m_vRealCornerID_quad.push_back(get_or_insert_vertex(this->m_vCornerCoords[i])); + } +} + +template +void InterfaceHandlerLocalDiffusion:: +Collect_Data_Nitsche(GridObject* elem) +{ + this->m_vInterfaceID.clear(); + +// collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *this->m_spMG, elem); + + this->m_vCornerCoords.clear(); + for(size_t i = 0; i < vVertex.size(); ++i) + this->m_vCornerCoords.push_back(this->m_aaPos[vVertex[i]]); + + int numFTVertex = 0; + for(size_t i = 0; i < vVertex.size(); ++i) + { + + // remember boolian for check, weather there existe at least one vertex, which is FT! + if ( this->is_onInterfaceVertex(vVertex[i], i) ) + numFTVertex++; + } + + m_vAlpha.clear(); + m_vIntersectionPnts.clear(); + + MathVector insidePnt_check; + + // collect all edges of the element + std::vector vEdges; + CollectEdgesSorted(vEdges, *this->m_spMG, elem); + + for(size_t e = 0; e < vEdges.size(); ++e) + { + Edge* edge = vEdges[e]; + std::vector vVertexEdge; + CollectVertices(vVertexEdge, *this->m_spMG, edge); + if ( vVertexEdge.size() != 2 ) + UG_THROW("error in collecting vertices associated to an edge!....EXIT!...\n"); + + Vertex* vrt1 = vVertexEdge[0]; + Vertex* vrt2 = vVertexEdge[1]; + size_t vrtInd1 = this->get_vertex_index(vrt1, elem); + size_t vrtInd2 = this->get_vertex_index(vrt2, elem); + + UG_LOG("m_aaPos[vrt1] = " << this->m_aaPos[vrt1][0] << ", m_aaPos[vrt1][1] = " << this->m_aaPos[vrt1][1] << "\n"); + UG_LOG("m_aaPos[vrt2] = " << this->m_aaPos[vrt2][0] << ", m_aaPos[vrt2][1] = " << this->m_aaPos[vrt2][1] << "\n"); + + std::vector alphaOut; + MathVector intersectionPnt; + bool bNearInterface = false; + + + /////////////////////////////////////////////////////////////////// + // lies vrtRoot on a cutted edge? + /////////////////////////////////////////////////////////////////// + // case1: vrtRoot is intersectionPnt with insideCorner = near_interface_corner => remove! + if ( this->is_nearInterfaceVertex(vrt2, vrtInd2) || this->is_nearInterfaceVertex(vrt1, vrtInd1) ) + { bNearInterface = true; continue; } + // case2: vert2 = outsideParticle && vrt1 = insideParticle: + else if ( this->is_onInterfaceVertex(vrt1, vrtInd1) && !this->is_onInterfaceVertex(vrt2, vrtInd2) ) + { + get_intersection_point(intersectionPnt, vrt2, vrt1, alphaOut); + UG_LOG("* alphaOut[0] = " << alphaOut[0] << ", alphaOut[1] = " << alphaOut[1] << "\n"); + UG_LOG("* intersectionPnt[0] = " << intersectionPnt[0] << ", intersectionPnt[1] = " << intersectionPnt[1] << "\n"); + m_vAlpha.push_back(alphaOut); + m_vIntersectionPnts.push_back(intersectionPnt); + m_vShapeValues[vrtInd2][vrtInd1] = alphaOut[0]; + m_vShapeValues[vrtInd1][vrtInd2] = alphaOut[1]; + if ( numFTVertex > 1 ) + { + m_insidePnt[0] = this->m_aaPos[vrt2][0]; + m_insidePnt[1] = this->m_aaPos[vrt2][1]; + } + else + { + m_insidePnt[0] = this->m_aaPos[vrt1][0]; + m_insidePnt[1] = this->m_aaPos[vrt1][1]; + } + this->m_vInterfaceID.push_back(vrtInd2); + } + // case3: vrt1 = outsideParticle && vrt2 = insideParticle: + else if ( this->is_onInterfaceVertex(vrt2, vrtInd2) && !this->is_onInterfaceVertex(vrt1, vrtInd1) ) + { + get_intersection_point(intersectionPnt, vrt1, vrt2, alphaOut); + UG_LOG("# alphaOut[0] = " << alphaOut[0] << ", alphaOut[1] = " << alphaOut[1] << "\n"); + UG_LOG("# intersectionPnt[0] = " << intersectionPnt[0] << ", intersectionPnt[1] = " << intersectionPnt[1] << "\n"); + m_vAlpha.push_back(alphaOut); + m_vIntersectionPnts.push_back(intersectionPnt); + m_vShapeValues[vrtInd1][vrtInd2] = alphaOut[0]; + m_vShapeValues[vrtInd2][vrtInd1] = alphaOut[1]; + if ( numFTVertex > 1 ) + { + insidePnt_check[0] = this->m_aaPos[vrt1][0]; + insidePnt_check[1] = this->m_aaPos[vrt1][1]; + } + else + { + insidePnt_check[0] = this->m_aaPos[vrt2][0]; + insidePnt_check[1] = this->m_aaPos[vrt2][1]; + } + this->m_vInterfaceID.push_back(vrtInd1); + } + else + { + alphaOut.clear(); alphaOut.push_back(0.0); alphaOut.push_back(0.0); + m_vAlpha.push_back(alphaOut); + m_vShapeValues[vrtInd1][vrtInd2] = 0.0; + m_vShapeValues[vrtInd2][vrtInd1] = 0.0; + continue; + } + + // check for correct inersectionPnt + if ( fabs(this->get_LSvalue_byPosition(intersectionPnt)) > 1e-6 ) + UG_THROW("in 'CollectIBCorners2d()': Error in computation of 'intersectionPnt':\n " + " intersectionPnt = " << intersectionPnt << "\n distance from interace = " << fabs(this->get_LSvalue_byPosition(intersectionPnt)) << "\n"); + + } // end edge-loop + +/* +// and copy data to m_vInterfaceID_tri: + m_vInterfaceID_tri.clear(); + for ( size_t i = 0; i < this->m_vInterfaceID.size(); ++i) + m_vInterfaceID_1.push_back(m_vInterfaceID[i]); +*/ +// check + if ( insidePnt_check[0] != m_insidePnt[0]) + { + UG_LOG("insidePnt_check[0] = " << insidePnt_check[0] << "\n"); + UG_LOG("m_insidePnt[0] = " << m_insidePnt[0] << "\n"); + } + if ( insidePnt_check[1] != m_insidePnt[1]) + { + UG_LOG("insidePnt_check[1] = " << insidePnt_check[1] << "\n"); + UG_LOG("m_insidePnt[1] = " << m_insidePnt[1] << "\n"); + } + +// set values to zero + m_vShapeValues[0][0] = m_vShapeValues[1][1] = m_vShapeValues[2][2] = 0.0; + +// compute area + if ( dim != 2 ) + UG_THROW(" for dim = 3 the implementatino needs to be adapted here!\n"); + + MathVector _x10, _x20; + MathVector x10, x20, n; + + VecSubtract(_x10, m_vIntersectionPnts[0], m_insidePnt); + VecSubtract(_x20, m_vIntersectionPnts[1], m_insidePnt); + for(size_t i = 0; i < dim; ++i) + { + x10[i] = _x10[i]; + x20[i] = _x20[i]; + } + x10[2] = x20[2] = 0.0; + + VecCross(n, x10, x20); + + m_Area = 0.5 * VecTwoNorm(n); + + VecSubtract(_x10, this->m_aaPos[vVertex[1]], this->m_aaPos[vVertex[0]]); + VecSubtract(_x20, this->m_aaPos[vVertex[2]], this->m_aaPos[vVertex[0]]); + for(size_t i = 0; i < dim; ++i) + { + x10[i] = _x10[i]; + x20[i] = _x20[i]; + } + x10[2] = x20[2] = 0.0; + + VecCross(n, x10, x20); + + m_AreaOrig = 0.5 * VecTwoNorm(n); + +// if numFTVertex = 1: m_Area needs to be the area of the remaining quadrilateral! + if ( numFTVertex == 1 ) + m_Area = m_AreaOrig - m_Area; + + m_AreaScale = m_Area/m_AreaOrig; + +// compute normal and Gamma + MathVector normal; + VecSubtract(normal, m_vIntersectionPnts[1], m_vIntersectionPnts[0]); + m_NormalToFace[0] = -normal[1]; + m_NormalToFace[1] = normal[0]; + + m_Gamma = sqrt(VecDot(m_NormalToFace,m_NormalToFace)); + +// compute integrals along Gamma + m_vIntegralGamma.clear(); m_vIntegralGamma.resize(3); + for(size_t i = 0; i < 3; ++i) + { + number valueSum = 0.0; + for(size_t j = 0; j < 3; ++j) + valueSum += m_vShapeValues[i][j]; + m_vIntegralGamma[i] = 0.5 * valueSum; //* m_Gamma; + } + + UG_LOG("m_insidePnt = " << m_insidePnt[0] << " , " << m_insidePnt[1] << "\n"); + UG_LOG("m_NormalToFace = " << m_NormalToFace[0] << " , " << m_NormalToFace[1] << "\n"); + UG_LOG("m_Gamma = " << m_Gamma << "\n"); + UG_LOG("m_Area = " << m_Area << "\n"); + UG_LOG("m_AreaOrig = " << m_AreaOrig << "\n"); + UG_LOG("m_AreaScale = " << m_AreaScale << "\n"); + + for(size_t e = 0; e < vEdges.size(); ++e) + { + UG_LOG("alphaOut[" << e << "] = " << m_vAlpha[e][0] << " , " << m_vAlpha[e][1] << "\n"); + UG_LOG("vIntersectionPnt[" << e << "] = " << m_vIntersectionPnts[e][0] << " , " << m_vIntersectionPnts[e][1] << "\n"); + } + + for(size_t vrtInd1 = 0; vrtInd1 < 3; ++vrtInd1) + { + for(size_t vrtInd2 = 0; vrtInd2 < 3; ++vrtInd2) + UG_LOG("m_vShapeValues[vrtInd1][vrtInd2] = " << m_vShapeValues[vrtInd1][vrtInd2] << "\n"); + UG_LOG("\n"); + } + for(size_t i = 0; i < 3; ++i) + UG_LOG("m_vIntegralGamma = " << m_vIntegralGamma[i] << "\n"); + +} + +template +int InterfaceHandlerLocalDiffusion:: +CollectCorners_FlatTop_2d(GridObject* elem) +{ + ////////////////////////////////////////////// + // 1) fill vector with fluid corners: + ////////////////////////////////////////////// + + this->m_vCornerCoords.clear(); + this->m_vInterfaceID.clear(); + this->m_vOriginalCornerID.clear(); + m_vRealCornerID_tri.clear(); + + +// buffer vectors for (cornerCoords, cornerIndex) + std::vector, size_t > > vOutsideCorners; + std::vector, size_t > > vInsideCorners; + std::vector, size_t > > vNearIntCorners; + std::vector vRealCornerID_tri; vRealCornerID_tri.clear(); + +// collect all vertices of the element + std::vector vVertex; + CollectVertices(vVertex, *this->m_spMG, elem); + + bool isFTVertex = false; + for(size_t i = 0; i < vVertex.size(); ++i) + { + // remember boolian for check, weather there existe at least one vertex, which is FT! + isFTVertex = this->is_onInterfaceVertex(vVertex[i], i); + if ( isFTVertex ) + break; + } + + if ( !isFTVertex ) + UG_THROW("Error in 'CollectCorners_FlatTop_2d': no vertex is FTVertex: should be true for at least 1 vertex!\n"); + + // collect all edges of the element + std::vector vEdges; + CollectEdgesSorted(vEdges, *this->m_spMG, elem); + + // loop vertices + ////////////////////////////////////////////// + // REMARK: + // order is the same as in 'vCornerCoords', therefore we can be sure, that the + // order of the new 'vCornerIBCoords' will be consistent with the grid standard + ////////////////////////////////////////////// + + bool bNearInterface = false; this->set_bNearInterface(false); + for(size_t i = 0; i < vVertex.size(); ++i) + { + Vertex* vrtRoot = vVertex[i]; + + ////////////////////////////////////////////// + // case 1: + // vertex insideDomain + if ( !this->is_onInterfaceVertex(vrtRoot, i) ) + { + if ( this->is_nearInterfaceVertex(vrtRoot, i) ) + UG_THROW("NearInterface BUT !is_FT => neuerdings Fehler!!....\n"); + + this->m_vCornerCoords.push_back(this->m_aaPos[vrtRoot]); + this->m_vOriginalCornerID.push_back(i); + vRealCornerID_tri.push_back(i); + + vInsideCorners.push_back(std::make_pair(this->m_aaPos[vrtRoot], i)); + } + ////////////////////////////////////////////// + // case 2: + // vertex = FT + ON interface + // => KEINE Berechnung von 'intersectionPoint' notwendig! -> pushen und alten index pushen + + // REMARK: is_nearInterfaceVerx = false per default, if m_vThresholdOnLevel = 0.0 + else if ( this->is_nearInterfaceVertex(vrtRoot, i) ) + { + bNearInterface = true; this->set_bNearInterface(true); + + this->m_vCornerCoords.push_back(this->m_aaPos[vrtRoot]); + this->m_vOriginalCornerID.push_back(i); + vRealCornerID_tri.push_back(i); + + this->m_vInterfaceID.push_back(this->m_vCornerCoords.size()-1); // attention: push AFTER 'm_vCornerCoords.push_back()'!! + + vOutsideCorners.push_back(std::make_pair(this->m_aaPos[vrtRoot], i)); + vNearIntCorners.push_back(std::make_pair(this->m_aaPos[vrtRoot], i)); + + get_or_insert_vertex(this->m_aaPos[vrtRoot]); + + } + ////////////////////////////////////////////// + // case 3: + // vertex 'outsideFluid' + // => NEUE Position berechen+pushen und alten index pushen + else + { + ////////////////////////////////////////////////////////////////////////////////////////// + // loop alle edges, die interface schneiden und damit einen neuen intersectionPnt + // beitragen zum damit assoziierten alten index + for(size_t e = 0; e < vEdges.size(); ++e) + { + Edge* edge = vEdges[e]; + std::vector vVertexEdge; + CollectVertices(vVertexEdge, *this->m_spMG, edge); + if ( vVertexEdge.size() != 2 ) + UG_THROW("error in collecting vertices associated to an edge!....EXIT!...\n"); + + Vertex* vrt1 = vVertexEdge[0]; + Vertex* vrt2 = vVertexEdge[1]; + size_t vrtInd1 = this->get_vertex_index(vrt1, elem); + size_t vrtInd2 = this->get_vertex_index(vrt2, elem); + + MathVector intersectionPnt; + + /////////////////////////////////////////////////////////////////// + // does vrtRoot lie on a cutted edge? + /////////////////////////////////////////////////////////////////// + // case1: vrtRoot is intersectionPnt with insideCorner = near_interface_corner => remove! + if ( this->is_nearInterfaceVertex(vrt2, vrtInd2) || this->is_nearInterfaceVertex(vrt1, vrtInd1) ) + { bNearInterface = true; this->set_bNearInterface(true); continue; } + // case2: vert2 = outsideParticle && vrt1 = insideParticle: + else if ( vrtRoot == vrt1 && !this->is_onInterfaceVertex(vrt2, vrtInd2) ){ + get_intersection_point(intersectionPnt, vrt2, vrt1); + } + // case3: vrt1 = outsideParticle && vrt2 = insideParticle: + else if ( vrtRoot == vrt2 && !this->is_onInterfaceVertex(vrt1, vrtInd1) ) + get_intersection_point(intersectionPnt, vrt1, vrt2); + else + continue; + + // check for correct inersectionPnt + if ( fabs(this->get_LSvalue_byPosition(intersectionPnt)) > 1e-6 ) + UG_THROW("in 'CollectIBCorners2d()': Error in computation of 'intersectionPnt':\n " + " intersectionPnt = " << intersectionPnt << "\n distance from interace = " << fabs(this->get_LSvalue_byPosition(intersectionPnt)) << "\n"); + + /////////////////////////////////////////////////////////////////// + // only push_back, if not included yet! + // -> can be ONLY the case, if the intersectionPoint is a node + if ( ! this->isIncluded(this->m_vCornerCoords, intersectionPnt) ) + { + + this->m_vCornerCoords.push_back(intersectionPnt); + this->m_vOriginalCornerID.push_back(i); + this->m_vInterfaceID.push_back(this->m_vCornerCoords.size()-1); // attention: push AFTER 'm_vCornerCoords.push_back()'!! + + vOutsideCorners.push_back(std::make_pair(intersectionPnt, i)); + + size_t index = get_or_insert_vertex(intersectionPnt); + vRealCornerID_tri.push_back(index); + + } + + + } // end edge-loop + + } // end else-case + + } // end vrt-loop + +//////////////////////////////////////////////////////////////////////////////////////////// +// Postprecessing for quadrilaterals ( <=> vOutsideCorners == 2 ) +// (vInsideCorners.size() == 2) && (bNearInterface) => ALL nodes insideFluid, BUT one ON surface +// => no Quadrilateral, but Triangle!! +//////////////////////////////////////////////////////////////////////////////////////////// + + MathVector normalDir(0.0); + if ( (this->m_vCornerCoords.size() == 4) && (!bNearInterface) && (dim == 2) ) + { + this->ResortQuadrilateral(vInsideCorners, vOutsideCorners, normalDir); + // and resort m_vRealCornerID_quad: + Resort_RealCornerID(); + // and copy data to m_vInterfaceID_quad: + m_vInterfaceID_quad.clear(); + for ( size_t i = 0; i < this->m_vInterfaceID.size(); ++i) + m_vInterfaceID_quad.push_back(this->m_vInterfaceID[i]); + } + else if ( bNearInterface && this->get_orientation() == -1 ) + { + // m_vRealCornerID_quad was not written and needs to be called: + // and copy data to m_vInterfaceID_tri: + Resort_RealCornerID(); + // and copy data to m_vInterfaceID_quad: + m_vInterfaceID_quad.clear(); + for ( size_t i = 0; i < this->m_vInterfaceID.size(); ++i) + m_vInterfaceID_quad.push_back(this->m_vInterfaceID[i]); + // Quadrilateral -> Triangle + if ( vInsideCorners.size() == 1 ) // case 1 + { + // do nothing, since re-sorting not necessary...??? + } + // skip whole element, since only FT points are included + else if ( vInsideCorners.size() == 0 ) + UG_THROW("in 'CollectCorners_FlatTop_2d()': vInsideCorners.size() " + "= " << vInsideCorners.size() << "not possible!\n"); + } + + if ( this->m_vCornerCoords.size() == 3 ) + { + // and copy data to m_vInterfaceID_tri: + m_vInterfaceID_tri.clear(); + for ( size_t i = 0; i < this->m_vInterfaceID.size(); ++i) + m_vInterfaceID_tri.push_back(this->m_vInterfaceID[i]); + // and copy data to m_vRealCornerID_tri: + m_vRealCornerID_tri.clear(); + for ( size_t i = 0; i < vRealCornerID_tri.size(); ++i) + m_vRealCornerID_tri.push_back(vRealCornerID_tri[i]); + } + + if ( this->m_vCornerCoords.size() == 0 ) + UG_THROW("m_vCornerCoords.size() = " << this->m_vCornerCoords.size() << "not possible!\n"); + + return this->m_vCornerCoords.size(); + +} + +template +void InterfaceHandlerLocalDiffusion:: +print_CutElementData() +{ + + const char* filename = "CutElementData."; + std::string name(filename); + char ext[50]; sprintf(ext, "txt"); + name.append(ext); + FILE* printFile = fopen(name.c_str(), "a"); + if ( dim == 3 ) + fprintf(printFile, "--------- New cut element --------\n\n"); + else if ( this->m_roid == ROID_QUADRILATERAL ) + fprintf(printFile, "--------- ROID_QUADRILATERAL --------\n\n"); + else if ( this->m_roid == ROID_TRIANGLE ) + fprintf(printFile, "------------ ROID_TRIANGLE ----------\n\n"); + + for ( size_t i = 0; i < this->m_vCornerCoords.size(); ++i ) + fprintf(printFile,"Cut element corner %lu: %e, %e \n", i, this->m_vCornerCoords[i][0], this->m_vCornerCoords[i][1]); + fprintf(printFile,"\n"); + + for(size_t i = 0; i < this->m_vOriginalCornerID.size(); ++i) + fprintf(printFile,"Original corner ID: %lu\n", this->m_vOriginalCornerID[i]); + fprintf(printFile,"\n"); + + for(size_t i = 0; i < this->m_vInterfaceID.size(); ++i) + fprintf(printFile,"Interface corner ID: %lu\n", this->m_vInterfaceID[i]); + fprintf(printFile,"\n"); + + + if ( InterfaceHandlerLocalBase::m_roid == ROID_TRIANGLE ) + { + for ( size_t i = 0; i < m_vInterfaceID_tri.size(); ++i ) + fprintf(printFile,"Interface corner ID - tri: %lu\n", m_vInterfaceID_tri[i]); + + for ( size_t i = 0; i < m_vRealCornerID_tri.size(); ++i ) + fprintf(printFile,"Real corner ID - tri: %lu\n", m_vRealCornerID_tri[i]); + } + + if ( InterfaceHandlerLocalBase::m_roid == ROID_QUADRILATERAL ) + { + for ( size_t i = 0; i < m_vInterfaceID_quad.size(); ++i ) + fprintf(printFile,"Interface corner ID - quad: %lu\n", m_vInterfaceID_quad[i]); + + for ( size_t i = 0; i < m_vRealCornerID_quad.size(); ++i ) + fprintf(printFile,"Real corner ID - quad: %lu\n", m_vRealCornerID_quad[i]); + } + + fclose(printFile); + +} + +template +void InterfaceHandlerLocalDiffusion:: +print_Nitsche_Data() +{ + for ( size_t i = 0; i < 3; ++i ) + UG_LOG("m_vAlpha = " << m_vAlpha[i][0] << "\t" << m_vAlpha[i][1] << "\n"); + UG_LOG("\n"); + + UG_LOG("vIntersectionPnt 1:" << m_vIntersectionPnts[0][0] << "\t" << m_vIntersectionPnts[0][1] << "\n"); + UG_LOG("vIntersectionPnt 2:" << m_vIntersectionPnts[1][0] << "\t" << m_vIntersectionPnts[1][1] << "\n"); + for(size_t vrtInd1 = 0; vrtInd1 < 3; ++vrtInd1) + { + for(size_t vrtInd2 = 0; vrtInd2 < 3; ++vrtInd2) + UG_LOG("m_vShapeValues[vrtInd1][vrtInd2] = " << m_vShapeValues[vrtInd1][vrtInd2] << "\n"); + UG_LOG("\n"); + } + UG_LOG("m_NormalToFace = " << m_NormalToFace[0] << " , " << m_NormalToFace[1] << "\n"); + UG_LOG("m_Gamma = " << m_Gamma << "\n"); + UG_LOG("m_Area = " << m_Area << "\n"); + UG_LOG("m_AreaOrig = " << m_AreaOrig << "\n"); + UG_LOG("m_AreaScale = " << m_AreaScale << "\n"); + +} + +} // end namespace ug + + + +#endif /* INTERFACE_HANDLER_LOCAL_DIFFUSION_TOOLS_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/interface_handler_diffusion_user_data.h b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/interface_handler_diffusion_user_data.h new file mode 100644 index 000000000..39ac24107 --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/interface_handler/interface_handler_two_sided_cut/interface_handler_diffusion_user_data.h @@ -0,0 +1,178 @@ +/* + * interface_handler_local_impl.h + * + * Created on: 19.01.2015 + * Author: suze + */ + +#ifndef INTERFACE_HANDLER_LOCAL_DIFFUSION_DATA_H_ +#define INTERFACE_HANDLER_LOCAL_DIFFUSION_DATA_H_ + + + +namespace ug{ + + +/////////////////////////////////////////////////////////////// +/// methods for class 'InterfaceHandlerLocalDiffusion' +/////////////////////////////////////////////////////////////// + + +/////////////////////////////////////////////////////////////// +/// hard coded boundary conditions +/////////////////////////////////////////////////////////////// + +template +inline double get_jump_value_ex3(const MathVector position, const MathVector center, const int orientation) +{ + + return 0.0; + + if ( orientation == 1) + return 0.0; + + double absValue = position[0]*position[0] + position[1]* position[1]; + double returnValue = exp(-absValue); + + return returnValue; +} + + + + + +template +inline double get_jump_value_const(const MathVector position, const MathVector center, const int orientation) +{ + return 0.0; + + double absValue = position[0]*position[0] + position[1]* position[1]; + double factor = 8*(2*absValue - position[0] - position[1]); + + return factor*exp(-absValue); + + double sum = position[0] + position[1]; + + double returnValue = log(absValue) - sin(sum); + + return returnValue; +} + + + + +template +inline double get_jump_grad_value_kappa_Frei(const MathVector position, const MathVector center, const int orientation) +{ + return 0.0; + + if ( orientation == 1) + return -1.0; + else + return -0.1; + +} + +template +inline double get_jump_grad_value_kappa_Frei_inverse(const MathVector position, const MathVector center, const int orientation) +{ + if ( orientation == 1) + return -1.0; + else + return -0.1; + +} + + + + +template +inline double get_source_kappa_konform(const MathVector position, const MathVector center, const int orientation) +{ + double center_x = 0.0; + double center_y = -0.0244; + + if ( orientation == 1) + { + return 16.0*16.0; + } + else + { + if ( orientation != -1) + UG_THROW("wrong orientation!\n"); + + double dist_x = position[0] - center_x; + double dist_y = position[1] - center_y; + double dist = sqrt(dist_x*dist_x+dist_y*dist_y); + + return 200*16*dist*dist; + + } + +} + + + +template +inline double get_source_kappa_Frei(const MathVector position, const MathVector center, const int orientation) +{ + double center_x = 0.0; //0.1; + double center_y = 0.0; //0.2; + double kappa_1 = 0.1; + double kappa_2 = 1.0; + + if ( orientation == 1) + { + double dist_x = position[0] - center_x; + double dist_y = position[1] - center_y; + double distSq = sqrt(dist_x*dist_x+dist_y*dist_y); + + return 2.0*16*kappa_1*kappa_2*distSq; + } + else + { + if ( orientation != -1) + UG_THROW("wrong orientation!\n"); + + return 4.0*kappa_1*kappa_2; + + } + +} + + +template +inline double get_source_kappa_Frei_inverse(const MathVector position, const MathVector center, const int orientation) +{ + double center_x = 0.1; + double center_y = 0.2; + + if ( orientation == 1) + { + return 1.0*1.0*4.0; + } + else + { + if ( orientation != -1) + UG_THROW("wrong orientation!\n"); + + double dist_x = position[0] - center_x; + double dist_y = position[1] - center_y; + double dist = sqrt(dist_x*dist_x+dist_y*dist_y); + + return 2.0*0.1*0.1*16*dist*dist; + + } + +} + + + + + + +} // end namespace ug + + + +#endif /* INTERFACE_HANDLER_LOCAL_DIFFUSION_DATA_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/interface_provider/interface_provider_base.h b/ugbase/lib_disc/spatial_disc/immersed_util/interface_provider/interface_provider_base.h new file mode 100644 index 000000000..ddac7f033 --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/interface_provider/interface_provider_base.h @@ -0,0 +1,39 @@ +/* + * interface_handler_local.h + * + * Created on: 15.01.2015 + * Author: suze + */ + +#ifndef INTERFACE_PROVIDER_H_ +#define INTERFACE_PROVIDER_H_ + +namespace ug{ + + +template +class IInterfaceProvider +{ + public: +/// world Dimension + static const int dim = TWorldDim; + +/// default constructor: + IInterfaceProvider(){}; + +/// destructor + + virtual ~IInterfaceProvider() {} + + virtual number get_LSvalue_byPosition(MathVector vrtPos, const int prtIndex) = 0; + virtual const int get_orientation() const= 0; + virtual void set_orientation(const int orientation) = 0; + +}; + + + +}// end namespace ug + + +#endif /* INTERFACE_PROVIDER_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/interface_provider/interface_provider_diffusion.h b/ugbase/lib_disc/spatial_disc/immersed_util/interface_provider/interface_provider_diffusion.h new file mode 100644 index 000000000..8bb7c9f6b --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/interface_provider/interface_provider_diffusion.h @@ -0,0 +1,81 @@ +/* + * interface_handler_local.h + * + * Created on: 15.01.2015 + * Author: suze + */ + +#ifndef INTERFACE_HANDLER_DIFFUSION_H_ +#define INTERFACE_HANDLER_DIFFUSION_H_ + +#include "interface_provider_particle.h" + + +namespace ug{ + + +template +class DiffusionInterfaceProvider : public ParticleProviderSphere +{ + + public: +/// world Dimension + static const int dim = TWorldDim; + +/// default constructor: + DiffusionInterfaceProvider() + { + this->clear(); + UG_LOG("DiffusionInterfaceProvider constructor\n"); + }; + +/// destructor + virtual ~DiffusionInterfaceProvider() {} + +// setter methods + void add(number radius, const MathVector& center) + { + // set given values: + this->m_vCenter.push_back(center); + this->m_vRadius.push_back(radius); + this->m_vDensity.push_back(1.0); + } + +// getter methods + number get_radius(int prtIndex) + { if ( (int)this->num_particles() > 1 ) + UG_THROW("DiffusionInterfaceProvider::num_particles(): number of given particles = " << this->num_particles() << " more than 1! ... not supposed to be!\n"); + return this->m_vRadius[prtIndex]; } + + number get_density(int prtIndex) + { if ( (int)this->num_particles() > 1 ) + UG_THROW("DiffusionInterfaceProvider::num_particles(): number of given particles = " << this->num_particles() << " more than 1! ... not supposed to be!\n"); + return this->m_vDensity[prtIndex]; } + + MathVector get_center(int prtIndex) + { if ( (int)this->num_particles() > 1 ) + UG_THROW("DiffusionInterfaceProvider::num_particles(): number of given particles = " << this->num_particles() << " more than 1! ... not supposed to be!\n"); + return this->m_vCenter[prtIndex]; } + +// output methods + void print() + { + UG_LOG(" +++++++++++++++++++++++++ Interface Info ++++++++++++++++++++++++++++++ \n"); + UG_LOG("+++ num_circles = " << this->num_particles() << "\n"); + for (size_t p = 0; p < this->num_particles(); ++p) + { + UG_LOG("+++ center = " << this->get_center(p) << "\n"); + UG_LOG("+++ radius = " << this->get_radius(p) << "\n"); + UG_LOG("+++ density = " << this->get_density(p) << "\n"); + } + UG_LOG(" ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \n"); + } + + +}; + + +}// end namespace ug + + +#endif /* INTERFACE_HANDLER_DIFFUSION_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/interface_provider/interface_provider_particle.h b/ugbase/lib_disc/spatial_disc/immersed_util/interface_provider/interface_provider_particle.h new file mode 100644 index 000000000..99d5eea97 --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/interface_provider/interface_provider_particle.h @@ -0,0 +1,370 @@ +/* + * moving_particle.h + * + * Created on: 20.01.2015 + * Author: suze + */ + +#ifndef INTERFACE_PROVIDER_PARTICLE_H_ +#define INTERFACE_PROVIDER_PARTICLE_H_ + + +#ifdef UG_PARALLEL + #include "lib_grid/parallelization/load_balancer_util.h" +#endif + + +namespace ug{ + +#include "interface_provider_base.h" + +template +class ParticleProvider : public IInterfaceProvider +{ + + public: +/// world Dimension + static const int dim = TWorldDim; + +/// default constructor: + ParticleProvider() + : m_prtIndex(-1), m_orientationInterface(1) + { + clear(); + UG_LOG("ParticleProvider constructor\n"); + }; + +/// destructor + virtual ~ParticleProvider() {} + +////////////////////////////////////////////////////////// +/// virtual base class methods, which need to be +/// implemented by derived class +////////////////////////////////////////////////////////// + +/// methods called by CutElementHandler: + virtual number get_LSvalue_byPosition(MathVector vrtPos) + { UG_THROW("in 'ParticleProvider::get_LSvalue_byPosition(vrtPos)': needs to be implemented by derived class!\n");} + + virtual number get_LSvalue_byPosition(MathVector vrtPos, const int prtIndex) + { UG_THROW("in 'ParticleProvider::get_LSvalue_byPosition(vrtPos, prtIndex)': needs to be implemented by derived class!\n");} + + virtual bool get_intersection_point(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, const int PrtIndex) + { UG_THROW("in 'ParticleProvider::get_intersection_point()': needs to be implemented by derived class!\n");} + + virtual bool get_intersection_point(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, const int PrtIndex, std::vector& alphaOut) + { UG_THROW("in 'ParticleProvider::get_intersection_point()': needs to be implemented by derived class!\n");} + +// updates the location of the interface for the next time step + virtual void update(number deltaT, const MathVector transSol, const MathVector rotSol, const int prtIndex) + { UG_THROW("in 'ParticleProvider::update()': needs to be implemented by derived class!\n");} + + + virtual number get_radius(int prtIndex) + { UG_THROW("in 'ParticleProvider::get_radius()': needs to be implemented by derived class!\n");} + + number get_theta(int prtIndex) + { UG_THROW("in 'ParticleProvider::get_theta()': needs to be implemented by derived class!\n");} + number set_theta(number theta, int prtIndex) + { UG_THROW("in 'ParticleProvider::get_theta()': needs to be implemented by derived class!\n");} + + virtual void print() + { UG_THROW("in 'ParticleProvider::print()': needs to be implemented by derived class!\n");} + +/// methods called by LocalToGlobalMapper: + virtual number Volume(int levIndex, size_t prtIndex) + { UG_THROW("in 'ParticleProvider::Volume()': needs to be implemented by derived class!\n");} + virtual number Mass(const int levIndex, const int prtIndex, const number fluidDensity) + { UG_THROW("in 'ParticleProvider::Mass()': needs to be implemented by derived class!\n");} + virtual number Mass(const int levIndex, const int prtIndex, const number volume, const number fluidDensity) + { UG_THROW("in 'ParticleProvider::Mass()': needs to be implemented by derived class!\n");} + virtual number MomOfInertia(const int levIndex, const int prtIndex, const number fluidDensity) + { UG_THROW("in 'ParticleProvider::MomOfInertia()': needs to be implemented by derived class!\n");} + virtual number MomOfInertia(const int levIndex, const int prtIndex, const number volume, const number fluidDensity) + { UG_THROW("in 'ParticleProvider::MomOfInertia()': needs to be implemented by derived class!\n");} + + + virtual void print_velocity(const MathVector& transSol, const MathVector& rotSol, const int prtIndex, const bool isTimedep, const number time, const char* filename) + { UG_THROW("in 'ParticleProvider::print_velocity()': needs to be implemented by derived class!\n");} + + +////////////////////////////////////////////////////////// +/// setter methods +////////////////////////////////////////////////////////// + + void set_density(number density, int prtIndex) + { + if ( (int)num_particles() < prtIndex ) + UG_THROW("ParticleProvider::set_density(): number of given particles = " + << num_particles() << " smaller than given prtIndex = " << prtIndex << "\n"); + m_vDensity[prtIndex] = density; + } + void set_center(MathVector center, int prtIndex) + { + if ( (int)num_particles() < prtIndex ) + UG_THROW("ParticleProvider::set_center(): number of given particles = " + << num_particles() << " smaller than given prtIndex = " << prtIndex << "\n"); + for ( size_t d = 0; d < dim; ++d ) + m_vCenter[prtIndex][d] = center[d]; + } + + void clear() + { + m_vDensity.clear(); m_vCenter.clear(); + m_vvLinearVelocity.clear(); m_vvAngularVelocity.clear(); + m_vGivenVelocity.clear(); + } + +////////////////////////////////////////////////////////// +/// setter methods +////////////////////////////////////////////////////////// + + size_t num_particles() const{ return m_vCenter.size(); } + + number get_density(int prtIndex){ return m_vDensity[prtIndex]; } + MathVector get_center(int prtIndex){ return m_vCenter[prtIndex]; } + bool get_DoF_modus_linear(int prtIndex) { return m_vGivenVelocity[prtIndex][0]; } + bool get_DoF_modus_angular(int prtIndex) { return m_vGivenVelocity[prtIndex][1]; } + +// getter and setter for orientation of the interface + const int get_prtIndex() const{ return m_prtIndex; } + void set_prtIndex(const int prtIndex) { m_prtIndex = prtIndex; } + + +// getter and setter for orientation of the interface + void set_orientation(const int orientation) { m_orientationInterface = orientation; } + const int get_orientation() const{ return m_orientationInterface; } + +// getter and setter for the velocity of the interface +// --> called during PartcleMapper::modify_GlobalSol(): + void set_linear_velocity(number solution, size_t prtIndex, int timeSeriesInd, int cmp) + { m_vvLinearVelocity[timeSeriesInd][prtIndex][cmp] = solution; } + void set_linear_velocity(MathVector solution, size_t prtIndex, int timeSeriesInd) + { m_vvLinearVelocity[timeSeriesInd][prtIndex] = solution; } + void set_angular_velocity(number solution, size_t prtIndex, int timeSeriesInd, int cmp) + { m_vvAngularVelocity[timeSeriesInd][prtIndex][cmp] = solution; } + void set_angular_velocity(MathVector solution, size_t prtIndex, int timeSeriesInd) + { m_vvAngularVelocity[timeSeriesInd][prtIndex] = solution; } + + MathVector get_linear_velocity(size_t prtIndex, size_t timeSeriesInd) + { return m_vvLinearVelocity[timeSeriesInd][prtIndex]; } + MathVector get_angular_velocity(size_t prtIndex, size_t timeSeriesInd) + { return m_vvAngularVelocity[timeSeriesInd][prtIndex]; } + + +protected: + std::vector m_vDensity; + std::vector > m_vCenter; + +// indexing: [TimeSeriesIndes][prtIndex]: + std::vector > > m_vvLinearVelocity; + std::vector > > m_vvAngularVelocity; + +// indexing: [prtIndex][linear/angular] + std::vector > m_vGivenVelocity; + + int m_prtIndex; + int m_orientationInterface; + +}; + + +template +class ParticleProviderSphere : public ParticleProvider +{ + +public: +/// world Dimension + static const int dim = TWorldDim; + +/// default constructor: + ParticleProviderSphere() : ParticleProvider() + { UG_LOG("ParticleProviderSphere constructor\n") }; + +/// destructor + virtual ~ParticleProviderSphere() {} + + +// initializing methods + void add (number radius, const MathVector& center, number density); + void add_moving(number radius, const MathVector& center, number density, + const MathVector& linearVel, const MathVector& angularVel); + + +/////////////////////////////////////////////////////////////////////////////////////// +// virtual base class methods (necessary to be implemented!) +/////////////////////////////////////////////////////////////////////////////////////// + + number get_LSvalue_byPosition(MathVector vrtPos); + number get_LSvalue_byPosition(MathVector vrtPos, const int prtIndex); + + bool get_intersection_point(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, const int prtIndex) + { return get_LineCircle_Intersection(Intersect, vrtPosOut, vrtPosIn, prtIndex);} + + bool get_intersection_point(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, const int prtIndex, std::vector& alphaOut) + { return get_LineCircle_Intersection(Intersect, vrtPosOut, vrtPosIn, prtIndex, alphaOut);} + + bool get_LineCircle_Intersection(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, int prtIndex); + bool get_LineCircle_Intersection(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, int prtIndex, std::vector& alphaOut); + +// updates the center of particle + void update(number deltaT, const MathVector transSol, const MathVector rotSol, const int prtIndex); + + void set_radius(number radius, int prtIndex) + { + if ( (int)this->num_particles() < prtIndex ) + UG_THROW("ParticleProviderSphere::set_radius(): number of given particles = " + << this->num_particles() << " smaller than given prtIndex = " << prtIndex << "\n"); + m_vRadius[prtIndex] = radius; + } + + number get_radius(int prtIndex){ return m_vRadius[prtIndex]; } + +/// methods called by class 'LocalToGlobalMapper': + number Volume(int levIndex, size_t prtIndex); + number Mass(const int levIndex, const int prtIndex, const number fluidDensity); + number Mass(const int levIndex, const int prtIndex, const number volume, const number fluidDensity); + number MomOfInertia(const int levIndex, const int prtIndex, const number fluidDensity); + number MomOfInertia(const int levIndex, const int prtIndex, const number volume, const number fluidDensity); + + void print(); + void print_velocity(const MathVector& transSol, const MathVector& rotSol, const int prtIndex, + const bool isTimedep, const number time, const char* filename); + +/////////////////////////////////////////////////////////////////////////////////////// +/// class member +/////////////////////////////////////////////////////////////////////////////////////// + + + protected: + std::vector m_vRadius; + + +}; + +template +class ParticleProviderEllipse : public ParticleProvider +{ + +public: +/// world Dimension + static const int dim = TWorldDim; + +/// default constructor: + ParticleProviderEllipse() : ParticleProvider() + { + this->clear(); + m_vEllipticAxis.clear(); + m_vTheta.clear(); + UG_LOG("ParticleProviderEllipse constructor\n"); + }; + +/// destructor + virtual ~ParticleProviderEllipse() {} + +// initializing methods + void add (const MathVector& ellipticAxis, const MathVector& center, const number theta, number density); + void add_moving(const MathVector& ellipticAxis, const MathVector& center, const number theta, number density, + const MathVector& linearVel, const MathVector& angularVel); + + +/////////////////////////////////////////////////////////////////////////////////////// +// virtual base class methods (necessary to be implemented!) +/////////////////////////////////////////////////////////////////////////////////////// + + number get_LSvalue_byPosition(MathVector vrtPos); + number get_LSvalue_byPosition(MathVector vrtPos, const int prtIndex); + + bool get_intersection_point(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, const int PrtIndex); + bool get_intersection_point(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, const int PrtIndex, std::vector& alphaOut); + + bool get_LineEllipse_Intersection(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, int PrtIndex); + // Old version of 'get_LineEllipse_Intersection': + bool get_LineEllipse_Intersection(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, int PrtIndex, std::vector& alphaOut); + +// returns a value, which substitutes the computation of an LSvalue, i.e.: +// return value > 0, if vrtPosOut on same side as vrtPosIn (= discriminant < 0) +// return value < 0, if vrtPosOut on other side as vrtPosIn (= discriminant > 0) + number IFF_LineEllipse_Intersection(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, int PrtIndex, std::vector& alphaOut); + +/// methods called by class 'DiffusionInterfaceMapper': + number Volume(int levIndex, size_t prtIndex); + number Mass(const int levIndex, const int prtIndex, const number fluidDensity); + number Mass(const int levIndex, const int prtIndex, const number volume, const number fluidDensity); + number MomOfInertia(const int levIndex, const int prtIndex, const number fluidDensity); + number MomOfInertia(const int levIndex, const int prtIndex, const number volume, const number fluidDensity); + + + void print(); + void print_velocity(const MathVector& transSol, const MathVector& rotSol, const int prtIndex, + const bool isTimedep, const number time, const char* filename); + + void update(number deltaT, const MathVector transSol, const MathVector rotSol, const int prtIndex); + + void set_theta(number theta, int prtIndex) + { + if ( (int)this->num_particles() < prtIndex ) + UG_THROW("EllipseProvider::set_theta(): number of given particles = " + << this->num_particles() << " smaller than given prtIndex = " << prtIndex << "\n"); + m_vTheta[prtIndex] = theta; + } + + number get_theta(int prtIndex){ return m_vTheta[prtIndex]; } + +/////////////////////////////////////////////////////////////////////////////////////// +// new getter methods +/////////////////////////////////////////////////////////////////////////////////////// + + MathVector get_elliptic_axis(int prtIndex){ return m_vEllipticAxis[prtIndex]; } + number get_elliptic_axis_x(int prtIndex){ return m_vEllipticAxis[prtIndex][0]; } + number get_elliptic_axis_y(int prtIndex){ return m_vEllipticAxis[prtIndex][1]; } + + void set_elliptic_axis(MathVector ellitpicAxis, int prtIndex) + { + if ( (int)this->num_particles() < prtIndex ) + UG_THROW("EllipseProvider::set_center(): number of given particles = " + << this->num_particles() << " smaller than given prtIndex = " << prtIndex << "\n"); + for ( size_t d = 0; d < dim; ++d ) + m_vEllipticAxis[prtIndex][d] = ellitpicAxis[d]; + } + + +/////////////////////////////////////////////////////////////////////////////////////// +// new methods +/////////////////////////////////////////////////////////////////////////////////////// + +// set vrtPos to origin and rotate by -theta + void rotate_vector(MathVector& vrtPos, const int prtIndex); + void rotate_vector_inverse(MathVector& vrtPos, const int prtIndex); + + +/////////////////////////////////////////////////////////////////////////////////////// +// class member +/////////////////////////////////////////////////////////////////////////////////////// + +protected: + std::vector > m_vEllipticAxis; + std::vector m_vTheta; + +}; + + +} // end namespace ug + + +#include "interface_provider_particle_sphere_impl.h" +#include "interface_provider_particle_ellipse_impl.h" + + +#endif /* INTERFACE_PROVIDER_PARTICLE_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/interface_provider/interface_provider_particle_ellipse_impl.h b/ugbase/lib_disc/spatial_disc/immersed_util/interface_provider/interface_provider_particle_ellipse_impl.h new file mode 100644 index 000000000..b10d314a3 --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/interface_provider/interface_provider_particle_ellipse_impl.h @@ -0,0 +1,524 @@ +/* + * moving_particle.h + * + * Created on: 20.01.2015 + * Author: suze + */ + +#ifndef INTERFACE_PROVIDER_PARTICLE_ELLIPSE_H_ +#define INTERFACE_PROVIDER_PARTICLE_ELLIPSE_H_ + + +namespace ug{ + +template +void ParticleProviderEllipse:: +add(const MathVector& ellipticAxis, const MathVector& center, const number theta, number density) +{ + // A. set given values: + this->m_vCenter.push_back(center); + m_vEllipticAxis.push_back(ellipticAxis); + m_vTheta.push_back(theta); + + this->m_vDensity.push_back(density); + std::vector bDummy(2,false); + this->m_vGivenVelocity.push_back(bDummy); + + // B. prepare data for free ellipse velocities, to be computed + // B1: resize velocity vectors for TimeSeries-Data + const size_t numTimePoints = 2; + this->m_vvLinearVelocity.resize(numTimePoints); + this->m_vvAngularVelocity.resize(numTimePoints); + + // B2: set dummy values if velocity of ellipse is free within fluid + const MathVector vDummy(0.0); + + for ( size_t i = 0; i < numTimePoints; ++i ) + { + this->m_vvLinearVelocity[i].push_back(vDummy); + this->m_vvAngularVelocity[i].push_back(vDummy); + } + +} + +template +void ParticleProviderEllipse:: +add_moving(const MathVector& ellipticAxis, const MathVector& center, const number theta, number density, + const MathVector& linearVel, const MathVector& angularVel) +{ + // A. set given values: + this->m_vCenter.push_back(center); + m_vEllipticAxis.push_back(ellipticAxis); + m_vTheta.push_back(theta); + + this->m_vDensity.push_back(density); + std::vector dummy(2,true); + this->m_vGivenVelocity.push_back(dummy); + + // B. prepare data to set ellipse velocities + // B1: resize velocity vectors for TimeSeries-Data + const size_t numTimePoints = 2; + this->m_vvLinearVelocity.resize(numTimePoints); + this->m_vvAngularVelocity.resize(numTimePoints); + + // B2: set ellipse velocities + for ( size_t i = 0; i < numTimePoints; ++i ) + { + this->m_vvLinearVelocity[i].push_back(linearVel); + this->m_vvAngularVelocity[i].push_back(angularVel); + } +} + + +// set vrtPos to origin and rotate by -theta +template +void ParticleProviderEllipse:: +rotate_vector(MathVector& vrtPos, const int prtIndex) +{ + const number theta = -1.0 * get_theta(prtIndex); + const number radians = theta * PI / 180.0; + const MathVector center = this->get_center(prtIndex); + +// first move vtPos to origin: + MathVector vrtPos_move; + VecSubtract(vrtPos_move, vrtPos, center); +// buffer values in order to overwrite them: + number vrtPos_x = vrtPos_move[0]; + number vrtPos_y = vrtPos_move[1]; + +// Rotate vrtPos by angle -theta: + vrtPos_move[0] = vrtPos_x * cos(radians) - vrtPos_y * sin(radians); + vrtPos_move[1] = vrtPos_x * sin(radians) + vrtPos_y * cos(radians); + +// now move vtPos back to center: + VecAdd(vrtPos, vrtPos_move, center); +} + +// set vrtPos to center and rotate by theta +template +void ParticleProviderEllipse:: +rotate_vector_inverse(MathVector& vrtPos, const int prtIndex) +{ + const number theta = 1.0 * get_theta(prtIndex); + const number radians = theta * PI / 180.0; + const MathVector center = this->get_center(prtIndex); + +// first move vtPos to origin: + MathVector vrtPos_move; + VecSubtract(vrtPos_move, vrtPos, center); +// buffer values in order to overwrite them: + number vrtPos_x = vrtPos_move[0]; + number vrtPos_y = vrtPos_move[1]; + +// Rotate vrtPos by angle theta: + vrtPos_move[0] = vrtPos_x * cos(radians) - vrtPos_y * sin(radians); + vrtPos_move[1] = vrtPos_x * sin(radians) + vrtPos_y * cos(radians); + +// now move vtPos to center: + VecAdd(vrtPos, vrtPos_move, center); + +} + + +template +void ParticleProviderEllipse:: +update(number deltaT, const MathVector transSol, const MathVector rotSol, const int prtIndex) +{ + // update center of particle + MathVector centerNew = this->get_center(prtIndex); + VecScaleAdd(centerNew, 1.0, centerNew, deltaT, transSol); + this->set_center(centerNew, prtIndex); + + // update theta of particle + number radianNew = get_theta(prtIndex)* PI / 180.0 + deltaT*rotSol[0]; + number thetaNew = radianNew * 180.0 / PI; + set_theta(thetaNew, prtIndex); + +} + +template +number ParticleProviderEllipse:: +get_LSvalue_byPosition(MathVector vrtPos) +{ + const int prtIndex = this->get_prtIndex(); + if ( prtIndex == -1 ) + UG_THROW("in 'ParticleProviderEllipse:get_LSvalue_byPosition(vrtPos)': call of get_LSvalue_byPosition() with prtIndex = " + << prtIndex << " not allowed!\n"); + + return get_LSvalue_byPosition(vrtPos, prtIndex); + +} + +template +number ParticleProviderEllipse:: +get_LSvalue_byPosition(MathVector vrtPos, const int prtIndex) +{ + if ( prtIndex == -1 ) + UG_THROW("in 'ParticleProviderEllipse:get_LSvalue_byPosition()': call of get_LSvalue_byPosition() with prtIndex = " + << prtIndex << " not allowed!\n"); +// A) get center of ellipse as reference point + const MathVector vrtPosIn = this->get_center(prtIndex); + MathVector intersectionPnt; + std::vector alphaOut; + alphaOut.resize(2,0.5); + +// B) Rotate vrtPos by angle -theta and set center of ellipse to origin: + rotate_vector(vrtPos, prtIndex); + +// C) Compute LS_value for rotated vrtPos: + number fake_LSvalue = IFF_LineEllipse_Intersection(intersectionPnt, vrtPos, vrtPosIn, prtIndex, alphaOut); + + return fake_LSvalue; + +} + +template +bool ParticleProviderEllipse:: +get_intersection_point(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, const int PrtIndex) +{ +// first rotate input points: + MathVector vrtPosOut_rotated = vrtPosOut; + MathVector vrtPosIn_rotated = vrtPosIn; + + rotate_vector(vrtPosOut_rotated, PrtIndex); + rotate_vector(vrtPosIn_rotated, PrtIndex); + +// returns intersection point already shifted back to real center!! + get_LineEllipse_Intersection(Intersect, vrtPosOut_rotated, vrtPosIn_rotated, PrtIndex); + +// NOW: rotate the intersection point BACK again!! +// ---> (in 'get_LineEllipse_Intersection()' Intersect mit Ellipse through origin! + rotate_vector_inverse(Intersect, PrtIndex); + + return true; +} + + +template +bool ParticleProviderEllipse:: +get_intersection_point(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, const int PrtIndex, std::vector& alphaOut) +{ +// first rotate input points: + MathVector vrtPosOut_rotated = vrtPosOut; + MathVector vrtPosIn_rotated = vrtPosIn; + + rotate_vector(vrtPosOut_rotated, PrtIndex); + rotate_vector(vrtPosIn_rotated, PrtIndex); + + // returns intersection point already shifted back to real center!! + get_LineEllipse_Intersection(Intersect, vrtPosOut_rotated, vrtPosIn_rotated, PrtIndex, alphaOut); + + // NOW: rotate the intersection point BACK again!! + // ---> (in 'get_LineEllipse_Intersection()' Intersect mit Ellipse through origin! + rotate_vector_inverse(Intersect, PrtIndex); + + return true; +} + +template +bool ParticleProviderEllipse:: +get_LineEllipse_Intersection(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, int PrtIndex) +{ + std::vector alphaOut; + alphaOut.clear(); + + return get_LineEllipse_Intersection(Intersect, vrtPosOut, vrtPosIn, PrtIndex, alphaOut); +} + +// Old version of 'get_LineEllipse_Intersection': +template +bool ParticleProviderEllipse:: +get_LineEllipse_Intersection(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, int PrtIndex, std::vector& alphaOut) +{ + /////////////////////////////////////////////////////////////////////////////////////// + // The parameterized equation for a line segment through the points (x1, y1) and (x2, y2) is: + // x(t) = x1 + (x2-x1)t + // y(t) = y1 + (y2-y1)t + // The following is the equation for an ellipse centered at the origin: + // (x/a)^2 + (y/b)^2 - 1 = 0 + // with a,b = elliptic axis + + // If you plug the equations for the line into the equation for the ellipse + // AND after some computations, we get a quadratic equation of the form: + // At^2 + Bt + C = 0 + // with A = ..., B = ..., C = ... ---> see below in the code;) + /////////////////////////////////////////////////////////////////////////////////////// + + number alpha; + + const number axis_x = get_elliptic_axis_x(PrtIndex); + const number axis_y = get_elliptic_axis_y(PrtIndex); + const MathVector& center = this->get_center(PrtIndex); + + // first move line by 'center'-vector, so that we can do the computations based on an ellipse with origin + MathVector vrtPosIn_move; + MathVector vrtPosOut_move; + VecSubtract(vrtPosIn_move, vrtPosIn, center); + VecSubtract(vrtPosOut_move, vrtPosOut, center); + + // lineDir = vrtPosIn_move - vrtPosOut_move; + MathVector lineDir; + VecSubtract(lineDir, vrtPosIn_move, vrtPosOut_move); + + const number a = (lineDir[0]*lineDir[0])/(axis_x*axis_x) + (lineDir[1]*lineDir[1])/(axis_y*axis_y); + const number b = 2*vrtPosOut_move[0]*lineDir[0]/(axis_x*axis_x) + 2*vrtPosOut_move[1]*lineDir[1]/(axis_y*axis_y); + const number c = (vrtPosOut_move[0]*vrtPosOut_move[0])/(axis_x*axis_x) + (vrtPosOut_move[1]*vrtPosOut_move[1])/(axis_y*axis_y) - 1.0; + + const number discriminant = b * b - 4 * a * c; + + // check that 'vrtPosOut' and 'vrtPosIn' really lie on different sides of the circle: + if (discriminant < -1e-8) + UG_THROW("Value of discriminant = " << discriminant << "\n"); + + // discriminant = 0! + const number alpha1 = (-b - sqrt(discriminant)) / (2.0 * a); + const number alpha2 = (-b + sqrt(discriminant)) / (2.0 * a); + + if (alpha1 <= alpha2) + alpha = alpha1; + else + alpha = alpha2; + + if (alpha < 0 || (alpha - 1.0) > 1e-8) + UG_THROW( + "Error in 'get_LineCircle_Intersection()': alpha not valid; should lie between 0 and 1: " << alpha << "\n"); + + for (size_t d = 0; d < dim; ++d) + Intersect[d] = vrtPosOut[d] + alpha * lineDir[d]; + + alphaOut.clear(); + alphaOut.push_back(alpha); + alphaOut.push_back(1.0 - alpha); + + return true; + +} + + + +// returns a value, which substitues the computation of an LSvalue, i.e.: +// return value > 0, if vrtPosOut on same side as vrtPosIn (= discriminant < 0) +// return value < 0, if vrtPosOut on other side as vrtPosIn (= discriminant > 0) +template +number ParticleProviderEllipse:: +IFF_LineEllipse_Intersection(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, int PrtIndex, std::vector& alphaOut) +{ + /////////////////////////////////////////////////////////////////////////////////////// + // The parameterized equation for a line segment through the points (x1, y1) and (x2, y2) is: + // x(t) = x1 + (x2-x1)t + // y(t) = y1 + (y2-y1)t + // The following is the equation for an ellipse centered at the origin: + // (x/axis_x)^2 + (y/axis_y)^2 - 1 = 0 + // with axis_x,axis_y = elliptic axis + + // If you plug the equations for the line into the equation for the ellipse + // AND after some computations, we get a quadratic equation of the form: + // at^2 + bt + c = 0 + // with a = ..., b = ..., c = ... ---> see below in the code;) + /////////////////////////////////////////////////////////////////////////////////////// + + const number axis_x = get_elliptic_axis_x(PrtIndex); + const number axis_y = get_elliptic_axis_y(PrtIndex); + const MathVector& center = this->get_center(PrtIndex); + + // first move line by 'center'-vector, so that we can do the computations based on an ellipse with origin + MathVector vrtPosIn_move; + MathVector vrtPosOut_move; + MathVector center_move; + VecSubtract(vrtPosIn_move, vrtPosIn, center); + VecSubtract(vrtPosOut_move, vrtPosOut, center); + VecSubtract(center_move, center, center); + + number factor1 = axis_x*axis_y; + number factor2 = sqrt(axis_x*axis_x*vrtPosOut_move[1]*vrtPosOut_move[1] + axis_y*axis_y*vrtPosOut_move[0]*vrtPosOut_move[0]); + number factor = factor1/factor2; + + Intersect[0] = factor * vrtPosOut_move[0]; + Intersect[1] = factor * vrtPosOut_move[1]; + + // compute distances to center for all 3 points: + number dist_vrtPosOut = VecDistance(vrtPosOut_move, center_move); + number dist_Intersect = VecDistance(Intersect, center_move); + + // first check, that 'Intersect' does not lie ON the interface + // ---> case relevant for check in 'CollectCorners_FlatTop_2d() + // ---> see 'interface_handler_particle_tools.h:CollectCorners_FlatTop_2d(): + /* + // check for correct inersectionPnt + if ( fabs(get_LSvalue_byPosition(intersectionPnt)) > 1e-6 ) + */ + + const number threshold_max = -1e+6; + if ( dist_Intersect < dist_vrtPosOut) + return -1e+6; + + + number dist1 = fabs(dist_Intersect - dist_vrtPosOut); + number dist__ = VecDistance(vrtPosOut_move, Intersect); + + if ( fabs(dist1 - dist__) > 1e-6) + UG_THROW("ohoh...in IFF_()\n"); + + if ( fabs(dist__ - 0.001) < 1e-6) + UG_LOG("stop! IFF_()\n"); + + return dist__; + + + + + + if ( fabs(dist_Intersect - dist_vrtPosOut) < 1e-6) + return 0.0; + + if ( dist_Intersect > dist_vrtPosOut) + { + return -threshold_max; + } + + return threshold_max; + +} + + +template +void ParticleProviderEllipse:: +print() +{ + UG_LOG(" +++++++++++++++++++++++++ ParticleProviderEllipse Info ++++++++++++++++++++++++++++++ \n"); + UG_LOG("+++ num_particles = " << this->num_particles() << "\n"); + for (size_t p = 0; p < this->num_particles(); ++p) + { + UG_LOG(" +++++++++++++++++++++++++ particle " << p << " ++++++++++++++++++++++++++++++ \n\n"); + + UG_LOG("+++ center = " << this->get_center(p) << "\n"); + UG_LOG("+++ density = " << this->get_density(p) << "\n"); + UG_LOG("+++ theta = " << get_theta(p) << "\n"); + UG_LOG("+++ elliptic_axis_x = " << get_elliptic_axis_x(p) << "\n"); + UG_LOG("+++ elliptic_axis_y = " << get_elliptic_axis_y(p) << "\n\n"); + + UG_LOG("+++ linear velocity: " << this->get_linear_velocity(p, 0) << "\n"); + UG_LOG("+++ angular velocity: " << this->get_angular_velocity(p, 0) << "\n\n"); + + } + UG_LOG(" ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \n"); +} + +template +void ParticleProviderEllipse:: +print_velocity(const MathVector& transSol, const MathVector& rotSol, const int prtIndex, const bool isTimedep, const number time, const char* filename) +{ + MathVector center = this->get_center(prtIndex); + + std::string name(filename); + + char * cstr = new char [name.size()+1]; + strcpy (cstr, name.c_str()); + + if ( !isTimedep ) + { + FILE* print_velocity = fopen(name.c_str(), "a"); + for ( int d = 0; d < dim; ++d ) fprintf(print_velocity,"%e \t %e \t ", transSol[d], rotSol[d]); + for ( int d = 0; d < dim; ++d ) fprintf(print_velocity,"%e \t ", center[d]); + fprintf(print_velocity," %e \t # transVel[0], rotVel[0], transVel[1], rotVel[1], center_coords, theta, (m_bSharedIP = ", get_theta(prtIndex)); + fprintf(print_velocity, "0 ) \n "); + fclose(print_velocity); + } + else + { + FILE* print_velocity = fopen(name.c_str(), "a"); + fprintf(print_velocity,"%e \t ",time); + for ( int d = 0; d < dim; ++d ) fprintf(print_velocity,"%e \t %e \t ", transSol[d], rotSol[d]); + for ( int d = 0; d < dim; ++d ) fprintf(print_velocity,"%e \t ", center[d]); + fprintf(print_velocity," %e \t # time, transVel[0], rotVel[0], transVel[1], rotVel[1], center_coords[0], center[1], theta", get_theta(prtIndex)); + fprintf(print_velocity, " \n "); + fclose(print_velocity); + } + +} + +template +number ParticleProviderEllipse:: +Volume(int levIndex, size_t prtIndex) +{ + const number axis_x = get_elliptic_axis_x(prtIndex); + const number axis_y = get_elliptic_axis_y(prtIndex); + + number volume; + + if ( dim == 2 ) + volume = 3.1415*axis_x*axis_y; + if ( dim == 3 ) + UG_THROW("in 'ParticleProviderEllipse::Volume()': 3d-case (i.e. axis_z) not implemented!\n"); + //volume = 4.0/3.0*3.1415*axis_x*axis_y*axis_z; + + return volume; +} + +template +number ParticleProviderEllipse:: +Mass(const int levIndex, const int prtIndex, const number fluidDensity) +{ + const number prtDensity = this->get_density(prtIndex); + const number effective_density = prtDensity - fluidDensity; + number mass = Volume(levIndex, prtIndex) * effective_density; + return mass; +} + +template +number ParticleProviderEllipse:: +Mass(const int levIndex, const int prtIndex, const number volume, const number fluidDensity) +{ + const number prtDensity = this->get_density(prtIndex); + const number effective_density = prtDensity - fluidDensity; + number mass = volume * effective_density; + + return mass; +} + +template +number ParticleProviderEllipse:: +MomOfInertia(const int levIndex, const int prtIndex, const number fluidDensity) +{ + const number axis_x = get_elliptic_axis_x(prtIndex); + const number axis_y = get_elliptic_axis_y(prtIndex); + + number momOfInertia; + + if ( dim == 2 ) momOfInertia = 0.25*axis_x*axis_y*Mass(levIndex, prtIndex, fluidDensity); + if ( dim == 3 ) + UG_THROW("in 'ParticleProviderEllipse::MomOfInertia()': 3d-case not implemented!\n"); + + return momOfInertia; +} + +template +number ParticleProviderEllipse:: +MomOfInertia(const int levIndex, const int prtIndex, const number volume, const number fluidDensity) +{ + const number axis_x = get_elliptic_axis_x(prtIndex); + const number axis_y = get_elliptic_axis_y(prtIndex); + + number momOfInertia; + + // I_x = 0.25 * pi * a * b^3 = 0.25 * b^2 * Area + // I_y = 0.25 * pi * b * a^3 = 0.25 * a^2 * Area + // => I_origin = I_x + I_y = 0.25 * (a^2+b^2) * Area + // => identical to MomOfInertia of Circle for a = b = r + if ( dim == 2 ) momOfInertia = 0.25*(axis_x*axis_x + axis_y*axis_y)*Mass(levIndex, prtIndex, volume, fluidDensity); + if ( dim == 3 ) + UG_THROW("in 'ParticleProviderEllipse::MomOfInertia()': 3d-case not implemented!\n"); + + return momOfInertia; +} + + +} // end namespace ug + + +#endif /* INTERFACE_PROVIDER_PARTICLE_ELLIPSE_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/immersed_util/interface_provider/interface_provider_particle_sphere_impl.h b/ugbase/lib_disc/spatial_disc/immersed_util/interface_provider/interface_provider_particle_sphere_impl.h new file mode 100644 index 000000000..b8996abc0 --- /dev/null +++ b/ugbase/lib_disc/spatial_disc/immersed_util/interface_provider/interface_provider_particle_sphere_impl.h @@ -0,0 +1,331 @@ +/* + * moving_particle.h + * + * Created on: 20.01.2015 + * Author: suze + */ + +#ifndef INTERFACE_PROVIDER_PARTICLE_SPHERE_H_ +#define INTERFACE_PROVIDER_PARTICLE_SPHERE_H_ + + +namespace ug{ + +template +void ParticleProviderSphere:: +add(number radius, const MathVector& center, number density) +{ + // A. set given values: + this->m_vCenter.push_back(center); + m_vRadius.push_back(radius); + this->m_vDensity.push_back(density); + std::vector bDummy(2,false); + this->m_vGivenVelocity.push_back(bDummy); + + // B. prepare data for free particle velocities, to be computed + // B1: resize velocity vectors for TimeSeries-Data + const size_t numTimePoints = 2; + this->m_vvLinearVelocity.resize(numTimePoints); + this->m_vvAngularVelocity.resize(numTimePoints); + + // B2: set dummy values if velocity of particle is free within fluid + const MathVector vDummy(0.0); + for ( size_t i = 0; i < numTimePoints; ++i ) + { + this->m_vvLinearVelocity[i].push_back(vDummy); + this->m_vvAngularVelocity[i].push_back(vDummy); + } + +} + +template +void ParticleProviderSphere:: +add_moving(number radius, const MathVector& center, number density, + const MathVector& linearVel, const MathVector& angularVel) +{ + // A. set given values: + this->m_vCenter.push_back(center); + m_vRadius.push_back(radius); + this->m_vDensity.push_back(density); + std::vector dummy(2,true); + this->m_vGivenVelocity.push_back(dummy); + + // B. prepare data to set particle velocities + // B1: resize velocity vectors for TimeSeries-Data + const size_t numTimePoints = 2; + this->m_vvLinearVelocity.resize(numTimePoints); + this->m_vvAngularVelocity.resize(numTimePoints); + + // B2: set particle velocities + for ( size_t i = 0; i < numTimePoints; ++i ) + { + this->m_vvLinearVelocity[i].push_back(linearVel); + this->m_vvAngularVelocity[i].push_back(angularVel); + } +} + +template +number ParticleProviderSphere:: +get_LSvalue_byPosition(MathVector vrtPos) +{ + const int prtIndex = this->get_prtIndex(); + if ( prtIndex == -1 ) + UG_THROW("in 'ParticleProviderSphere:get_LSvalue_byPosition(vrtPos)': call of get_LSvalue_byPosition() with prtIndex = " + << prtIndex << " not allowed!\n"); + + return get_LSvalue_byPosition(vrtPos, prtIndex); +} + +template +number ParticleProviderSphere:: +get_LSvalue_byPosition(MathVector vrtPos, const int prtIndex) +{ + if ( prtIndex == -1 ) + UG_THROW("in 'ParticleProviderSphere:get_LSvalue_byPosition(vrtPos, prtIndex)': call of get_LSvalue_byPosition() with prtIndex = " + << prtIndex << " not allowed!\n"); + + const number radius = get_radius(prtIndex); + const MathVector& center = this->get_center(prtIndex); + + MathVector localCoords; + VecSubtract(localCoords, vrtPos, center); + + number dist = VecDot(localCoords, localCoords); + dist = sqrt(dist); + + return radius - dist; + +} + +template +void ParticleProviderSphere:: +update(number deltaT, const MathVector transSol, const MathVector rotSol, const int prtIndex) +{ + MathVector centerNew = this->get_center(prtIndex); + VecScaleAdd(centerNew, 1.0, centerNew, deltaT, transSol); + this->set_center(centerNew, prtIndex); +} + + + +template +number ParticleProviderSphere:: +Volume(int levIndex, size_t prtIndex) +{ + const number radius = get_radius(prtIndex); + number volume = 0.0; + + if ( dim == 2 ) + volume = 3.1415*radius*radius; + if ( dim == 3 ) + volume = 4.0/3.0*3.1415*radius*radius*radius; + + return volume; +} + +template +number ParticleProviderSphere:: +Mass(const int levIndex, const int prtIndex, const number fluidDensity) +{ + const number prtDensity = this->get_density(prtIndex); + const number effective_density = prtDensity - fluidDensity; + number mass = Volume(levIndex, prtIndex) * effective_density; + return mass; +} + +template +number ParticleProviderSphere:: +Mass(const int levIndex, const int prtIndex, const number volume, const number fluidDensity) +{ + const number prtDensity = this->get_density(prtIndex); + const number effective_density = prtDensity - fluidDensity; + number mass = volume * effective_density; + + return mass; +} + +template +number ParticleProviderSphere:: +MomOfInertia(const int levIndex, const int prtIndex, const number fluidDensity) +{ + const number radius = get_radius(prtIndex); + number momOfInertia = 0.0; + + if ( dim == 2 ) momOfInertia = 0.5*radius*radius*Mass(levIndex, prtIndex, fluidDensity); + if ( dim == 3 ) momOfInertia = 0.4*radius*radius*Mass(levIndex, prtIndex, fluidDensity); + + return momOfInertia; +} + +template +number ParticleProviderSphere:: +MomOfInertia(const int levIndex, const int prtIndex, const number volume, const number fluidDensity) +{ + const number radius = get_radius(prtIndex); + number momOfInertia = 0.0; + + if ( dim == 2 ) momOfInertia = 0.5*radius*radius*Mass(levIndex, prtIndex, volume, fluidDensity); + if ( dim == 3 ) momOfInertia = 0.4*radius*radius*Mass(levIndex, prtIndex, volume, fluidDensity); + + return momOfInertia; +} + + +template +bool ParticleProviderSphere:: +get_LineCircle_Intersection(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, int PrtIndex) +{ + std::vector alphaOut; + alphaOut.clear(); + + return get_LineCircle_Intersection(Intersect, vrtPosOut, vrtPosIn, PrtIndex, alphaOut); +} + +template +bool ParticleProviderSphere:: +get_LineCircle_Intersection(MathVector& Intersect, const MathVector& vrtPosOut, + const MathVector& vrtPosIn, int prtIndex, std::vector& alphaOut) +{ + + /////////////////////////////////////////////////////////////////////////////////////// + // + // 'vrtPosOut':= the starting point of the ray, + // 'vrtPosIn' := the end point of the ray, + // 'center' := the center of sphere you're testing against + // 'radius' := the radius of that sphere + // 'lineDir' := direction vector of ray from start to end + // 'rayDir' := direction vector of ray from center to start + // + // Ansatz: + // (1) Intersect = vrtPosOut + alpha*lineDir + // (2) Intersect - center = radius + // + // => (1) Intersect[0] = vrtPosOut[0] + alpha*lineDir[0] + // Intersect[1] = vrtPosOut[1] + alpha*lineDir[1] + // => (2) (Intersect[0] - center[0])^2 + (Intersect[1] - center[1])^2 = radius^2 + // + // Plug (1) into (2) => ... => quadratic equation for alpha: + // + // alpha^2 * + alpha * 2* + ( -radius^2 ) = 0 + // + // -> a = , b = , c = - radius^2 + // + // + // => from (1): Intersect = vrtPosOut + alpha*(vrtPosIn - vrtPosOut) + /////////////////////////////////////////////////////////////////////////////////////// + + number alpha; + + const number radius = get_radius(prtIndex); + const MathVector& center = this->get_center(prtIndex); + + MathVector lineDir; + MathVector rayDir; + + // lineDir = vrtPosIn - vrtPosOut; + VecSubtract(lineDir, vrtPosIn, vrtPosOut); + // rayDir = vrtPosOut - center; + VecSubtract(rayDir, vrtPosOut, center); + + const number a = VecDot(lineDir, lineDir); + const number b = 2.0 * VecDot(lineDir, rayDir); + const number c = VecDot(vrtPosOut, vrtPosOut) + VecDot(center, center) + - 2 * VecDot(vrtPosOut, center) - radius * radius; + + const number discriminant = b * b - 4 * a * c; + + // check that 'vrtPosOut' and 'vrtPosIn' really lie on different sides of the circle: + if (discriminant < -1e-8) + UG_THROW("Value of discriminant = " << discriminant << "\n"); + + // discriminant = 0! + const number alpha1 = (-b - sqrt(discriminant)) / (2.0 * a); + const number alpha2 = (-b + sqrt(discriminant)) / (2.0 * a); + + if (alpha1 <= alpha2) + alpha = alpha1; + else + alpha = alpha2; + + if (alpha < 0 || (alpha - 1.0) > 1e-8) + UG_THROW("Error in 'get_LineCircle_Intersection()': alpha not valid;" + "should lie between 0 and 1: " << alpha << "\n"); + + for (size_t d = 0; d < dim; ++d) + Intersect[d] = vrtPosOut[d] + alpha * lineDir[d]; + + alphaOut.clear(); + alphaOut.push_back(alpha); + alphaOut.push_back(1.0 - alpha); + + return true; +} + + +template +void ParticleProviderSphere:: +print() +{ + UG_LOG(" +++++++++++++++++++++++++ ParticleProviderSphere Info ++++++++++++++++++++++++++++++ \n"); + UG_LOG("+++ num_particles = " << this->num_particles() << "\n"); + for (size_t p = 0; p < this->num_particles(); ++p) + { + UG_LOG(" +++++++++++++++++++++++++ particle " << p << " ++++++++++++++++++++++++++++++ \n\n"); + + UG_LOG("+++ center = " << this->get_center(p) << "\n"); + UG_LOG("+++ density = " << this->get_density(p) << "\n"); + UG_LOG("+++ radius = " << get_radius(p) << "\n\n"); + + UG_LOG("+++ linear velocity: " << this->get_linear_velocity(p, 0) << "\n"); + UG_LOG("+++ angular velocity: " << this->get_angular_velocity(p, 0) << "\n\n"); + + } + UG_LOG(" ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ \n"); +} + +template +void ParticleProviderSphere:: +print_velocity(const MathVector& transSol, const MathVector& rotSol, const int prtIndex, + const bool isTimedep, const number time, const char* filename) +{ + MathVector center = this->get_center(prtIndex); + const number radius = get_radius(prtIndex); + + number f1 = 0.0; + number gravity = -9.81; + if ( !isTimedep ) + f1 = transSol[0]*4.0/(radius*radius*gravity); + + std::string name(filename); + + char * cstr = new char [name.size()+1]; + strcpy (cstr, name.c_str()); + + if ( !isTimedep ) + { + FILE* print_velocity = fopen(name.c_str(), "a"); + fprintf(print_velocity,"%e \t %e \t ",radius, f1); + for ( int d = 0; d < dim; ++d ) fprintf(print_velocity,"%e \t %e \t ", transSol[d], rotSol[d]); + for ( int d = 0; d < dim; ++d ) fprintf(print_velocity,"%e \t ", center[d]); + fprintf(print_velocity," # radius, f1, transVel[0], rotVel[0], transVel[1], rotVel[1], center_coords, (m_bSharedIP = "); + fprintf(print_velocity, "0 ) \n "); + fclose(print_velocity); + } + else + { + FILE* print_velocity = fopen(name.c_str(), "a"); + fprintf(print_velocity,"%e \t ",time); + for ( int d = 0; d < dim; ++d ) fprintf(print_velocity,"%e \t %e \t ", transSol[d], rotSol[d]); + for ( int d = 0; d < dim; ++d ) fprintf(print_velocity,"%e \t ", center[d]); + fprintf(print_velocity," # time, transVel[0], rotVel[0], transVel[1], rotVel[1], center_coords[0], center[1]"); + fprintf(print_velocity, " \n "); + fclose(print_velocity); + } + +} + +} // end namespace ug + + +#endif /* INTERFACE_PROVIDER_PARTICLE_SPHERE_H_ */ diff --git a/ugbase/lib_disc/spatial_disc/local_to_global/local_to_global_mapper.h b/ugbase/lib_disc/spatial_disc/local_to_global/local_to_global_mapper.h index 656e5ea6e..cd1850e66 100644 --- a/ugbase/lib_disc/spatial_disc/local_to_global/local_to_global_mapper.h +++ b/ugbase/lib_disc/spatial_disc/local_to_global/local_to_global_mapper.h @@ -38,6 +38,8 @@ // intern headers #include "lib_disc/dof_manager/dof_distribution.h" +#include "lib_disc/time_disc/solution_time_series.h" + namespace ug{ @@ -70,8 +72,26 @@ class ILocalToGlobalMapper virtual void add_local_mat_to_global(matrix_type& mat, const LocalMatrix& lmat, ConstSmartPtr dd) = 0; - /// modifies local solution vector for adapted defect computation - virtual void modify_LocalSol(LocalVector& vecMod, const LocalVector& lvec, ConstSmartPtr dd) = 0; + /// sets certain entries to Dirichlet DoFs (in elem_disc_assembla_util) + virtual void adjust_mat_global(matrix_type& mat, const LocalMatrix& lmat, + ConstSmartPtr dd) = 0; + + /// modifies local solution vector for adapted defect computation ( in elem_disc_assemble_util) + virtual void modify_LocalData(LocalMatrix& locJ, LocalVector& locU, + ConstSmartPtr dd) = 0; + virtual void modify_LocalData(LocalVectorTimeSeries& uT, LocalMatrix& locJ, LocalVector& locU, + ConstSmartPtr dd) = 0; + + virtual void modify_LocalData(LocalVector& locD, LocalVector& tmpLocD, LocalVector& locU, + ConstSmartPtr dd) = 0; + virtual void modify_LocalData(LocalVectorTimeSeries& uT, LocalVector& locD, LocalVector& tmpLocD, LocalVector& locU, + ConstSmartPtr dd, size_t t) = 0; + + /// modifies global solution vector for adapted defect computation (in domain_disc_impl) + virtual void modify_GlobalSol(vector_type& vecMod, const vector_type& vec, ConstSmartPtr dd) = 0; + + virtual void modify_GlobalSol(SmartPtr > vSolMod, + ConstSmartPtr > vSol, ConstSmartPtr dd) = 0; /// virtual destructor virtual ~ILocalToGlobalMapper() {}; diff --git a/ugbase/lib_grid/algorithms/subdivision/subdivision_volumes.h b/ugbase/lib_grid/algorithms/subdivision/subdivision_volumes.h index f89ce1b1d..877923807 100644 --- a/ugbase/lib_grid/algorithms/subdivision/subdivision_volumes.h +++ b/ugbase/lib_grid/algorithms/subdivision/subdivision_volumes.h @@ -193,6 +193,22 @@ void CalculateSmoothManifoldPosInParentLevelButterflyScheme(MultiGrid& mg, TAPos AInt& aNumManifoldEdges); +/// Parent level vertex smoothing function for subdivision surfaces refinement (Butterfly scheme) +/** This function calculates the smoothed positions of all parent level vertices + * determined by the subdivision surfaces refinement. + * + * @param mg reference to MultiGrid + * @param markSH reference to SubsetHandler markSH containing marked (inner) boundary manifold + * @param linearManifoldSH reference to user-specified linearManifoldSubsets SubsetHandler + * @param aSmoothBndPosOddVrt reference to aSmoothBndPosOddVrt + * @param aNumManifoldEdges reference to aNumManifoldEdges +**/ +void CalculateSmoothManifoldPosInParentLevelButterflyScheme3d(MultiGrid& mg, MGSubsetHandler& markSH, + MGSubsetHandler& linearManifoldSH, + APosition& aSmoothBndPosOddVrt, + AInt& aNumManifoldEdges); + + /// Toplevel vertex smoothing function for subdivision surfaces refinement (Averaging scheme) /** This function calculates the smoothed positions of all toplevel vertices * determined by the subdivision surfaces refinement. @@ -314,6 +330,19 @@ void ApplySmoothManifoldPosToTopLevelButterflyScheme(MultiGrid& mg, TAPosition& MGSubsetHandler& linearManifoldSH); +/// Toplevel vertex repositioning function for subdivision surfaces refinement (Butterfly scheme) +/** This function repositions all toplevel manifold vertices to their smoothed positions + * determined by the subdivision surfaces refinement. + * + * @param mg reference to MultiGrid + * @param markSH reference to SubsetHandler markSH containing marked (inner) boundary manifold + * @param linearManifoldSH reference to user-specified linearManifoldSubsets SubsetHandler + * @param aSmoothBndPosOddVrt reference to aSmoothBndPosOddVrt +**/ +void ApplySmoothManifoldPosToTopLevelButterflyScheme3d(MultiGrid& mg, MGSubsetHandler& markSH, + MGSubsetHandler& linearManifoldSH); + + /// Toplevel vertex repositioning function for subdivision surfaces refinement (Averaging scheme) /** This function repositions all toplevel manifold vertices to their smoothed positions * determined by the subdivision surfaces refinement.