Beispiel #1
0
func main() {

	// input data
	fn, fnk := io.ArgToFilename(0, "nurbs01", ".msh", true)
	ctrl := io.ArgToBool(1, true)
	ids := io.ArgToBool(2, true)
	useminmax := io.ArgToBool(3, false)
	axisequal := io.ArgToBool(4, true)
	xmin := io.ArgToFloat(5, 0)
	xmax := io.ArgToFloat(6, 0)
	ymin := io.ArgToFloat(7, 0)
	ymax := io.ArgToFloat(8, 0)
	eps := io.ArgToBool(9, false)
	npts := io.ArgToInt(10, 41)

	// print input table
	io.Pf("\n%s\n", io.ArgsTable("INPUT ARGUMENTS",
		"mesh filename", "fn", fn,
		"show control points", "ctrl", ctrl,
		"show ids", "ids", ids,
		"use xmin,xmax,ymin,ymax", "useminmax", useminmax,
		"enforce axis.equal", "axisequal", axisequal,
		"min(x)", "xmin", xmin,
		"max(x)", "xmax", xmax,
		"min(y)", "ymin", ymin,
		"max(y)", "ymax", ymax,
		"generate eps instead of png", "eps", eps,
		"number of divisions", "npts", npts,
	))

	// load nurbss
	B := gm.ReadMsh(fnk)

	// plot
	if eps {
		plt.SetForEps(0.75, 500)
	} else {
		plt.SetForPng(0.75, 500, 150)
	}
	for _, b := range B {
		if ctrl {
			b.DrawCtrl2d(ids, "", "")
		}
		b.DrawElems2d(npts, ids, "", "")
	}
	if axisequal {
		plt.Equal()
	}
	if useminmax {
		plt.AxisRange(xmin, xmax, ymin, ymax)
	}
	ext := ".png"
	if eps {
		ext = ".eps"
	}
	plt.Save(fnk + ext)
}
Beispiel #2
0
func main() {

	// catch errors
	defer func() {
		if err := recover(); err != nil {
			if mpi.Rank() == 0 {
				chk.Verbose = true
				for i := 8; i > 3; i-- {
					chk.CallerInfo(i)
				}
				io.PfRed("ERROR: %v\n", err)
			}
		}
		mpi.Stop(false)
	}()
	mpi.Start(false)

	// default input parameters

	// read input parameters
	fnamepath, _ := io.ArgToFilename(0, "", ".sim", true)
	verbose := io.ArgToBool(1, true)
	erasePrev := io.ArgToBool(2, true)
	saveSummary := io.ArgToBool(3, true)
	allowParallel := io.ArgToBool(4, true)
	alias := io.ArgToString(5, "")

	// message
	if mpi.Rank() == 0 && verbose {
		io.PfWhite("\nGofem v3 -- Go Finite Element Method\n\n")
		io.Pf("Copyright 2015 Dorival Pedroso and Raul Durand. All rights reserved.\n")
		io.Pf("Use of this source code is governed by a BSD-style\n")
		io.Pf("license that can be found in the LICENSE file.\n\n")

		io.Pf("\n%v\n", io.ArgsTable(
			"filename path", "fnamepath", fnamepath,
			"show messages", "verbose", verbose,
			"erase previous results", "erasePrev", erasePrev,
			"save summary", "saveSummary", saveSummary,
			"allow parallel run", "allowParallel", allowParallel,
			"word to add to results", "alias", alias,
		))
	}

	// profiling?
	defer utl.DoProf(false)()

	// analysis data
	readSummary := false
	analysis := fem.NewFEM(fnamepath, alias, erasePrev, saveSummary, readSummary, allowParallel, verbose, 0)

	// run simulation
	err := analysis.Run()
	if err != nil {
		chk.Panic("Run failed:\n%v", err)
	}
}
Beispiel #3
0
func (o Input) String() (l string) {
	l = io.ArgsTable(
		"input filename", "inpfn", o.inpfn,
		"directory with .sim and .pat files", "Dir", o.Dir,
		"simulation filename", "SimFn", o.SimFn,
		"material name", "MatName", o.MatName,
		"path filename", "PathFn", o.PathFn,
		"plot set", "PlotSet", io.Sf("%v", o.PlotSet),
		"fig: generate .eps instead of .png", "FigEps", o.FigEps,
		"fig: proportion of figure", "FigProp", o.FigProp,
		"fig: width  of figure", "FigWid", o.FigWid,
	)
	return
}
Beispiel #4
0
func main() {

	// catch errors
	defer func() {
		if err := recover(); err != nil {
			io.PfRed("ERROR: %v\n", err)
		}
	}()

	// input data
	var mshfn string
	mshfn, fnkey = io.ArgToFilename(0, "data/d2-coarse", ".msh", true)
	io.Pf("\n%s\n", io.ArgsTable(
		"mesh filename", "mshfn", mshfn,
	))

	// read mesh
	msh, err := inp.ReadMsh("", mshfn, 0)
	if err != nil {
		io.PfRed("cannot read mesh:\n%v", err)
		return
	}
	ndim = msh.Ndim
	verts = msh.Verts
	cells = msh.Cells
	dirout = "/tmp/gofem"

	// buffers
	geo := new(bytes.Buffer)
	vtu := new(bytes.Buffer)

	// generate topology
	topology(geo)

	// points data
	pdata_write(vtu)

	// cells data
	cdata_write(vtu)

	// write vtu file
	vtu_write(geo, vtu)
}
Beispiel #5
0
func main() {

	// catch errors
	defer func() {
		if err := recover(); err != nil {
			io.PfRed("ERROR: %v\n", err)
		}
	}()

	// input data
	simfile, _ := io.ArgToFilename(0, "simfile.sim", true)
	zmin := io.ArgToFloat(1, 0.0)
	zmax := io.ArgToFloat(2, 3.0)
	npts := io.ArgToInt(3, 11)
	io.Pf("\n%s\n", io.ArgsTable(
		"simulation filename", "simfile", simfile,
		"min elevation", "zmin", zmin,
		"max elevation", "zmax", zmax,
		"number of points", "npts", npts,
	))

	// sim file
	sim := inp.ReadSim("", simfile, false)
	if sim == nil {
		io.PfRed("cannot read sim file\n")
		return
	}

	// layer
	var lay fem.GeoLayer
	lay.Zmin = zmin
	lay.Zmax = zmax
	lay.Cl = sim.WaterRho0 / sim.WaterBulk
	//if !lay.ReadPorousParameters(sim.Regions[0],
	// TODO

}
Beispiel #6
0
func main() {

	// catch errors
	defer func() {
		if err := recover(); err != nil {
			io.PfRed("ERROR: %v\n", err)
		}
	}()

	// input data
	matOld := io.ArgToString(0, "matOld.mat")
	matNew := io.ArgToString(1, "matNew.mat")
	convSymb := io.ArgToBool(2, true)
	io.Pf("\n%s\n", io.ArgsTable(
		"old material filename", "matOld", matOld,
		"new material filenamen", "matNew", matNew,
		"do convert symbols", "convSymb", convSymb,
	))

	// convert old => new
	inp.MatfileOld2New("", matNew, matOld, convSymb)
	io.Pf("conversion successful\n")
	io.Pfblue2("file <matNew.mat> created\n")
}
Beispiel #7
0
func main() {

	// catch errors
	defer func() {
		if err := recover(); err != nil {
			io.PfRed("ERROR: %v\n", err)
		}
	}()

	// input data
	filename, fnkey := io.ArgToFilename(0, "data/equations.txt", "", true)
	io.Pf("\n%s\n", io.ArgsTable("INPUT ARGUMENTS",
		"file with equations", "filename", filename,
	))

	io.Pforan("fnkey = %v\n", fnkey)

	// open file
	f, err := io.OpenFileR(filename)
	if err != nil {
		return
	}

	// constants
	MAXNIDX := 100
	INDICES := []string{"i", "j", "k", "l", "m", "n", "r", "s", "p", "q"}

	// read file
	var buf bytes.Buffer
	io.ReadLinesFile(f, func(idx int, line string) (stop bool) {

		// indices
		l := line
		for i := 0; i < MAXNIDX; i++ {
			l = strings.Replace(l, io.Sf("[%d]", i), io.Sf("_{%d}", i), -1)
		}
		for _, idx := range INDICES {
			l = strings.Replace(l, io.Sf("[%s]", idx), io.Sf("_{%s}", idx), -1)
		}

		// constants
		l = strings.Replace(l, "math.Sqrt2", "\\sqrt{2}", -1)
		l = strings.Replace(l, "SQ2", "\\sqrt{2}", -1)

		// functions
		l = strings.Replace(l, "math.Sqrt", "\\sqrt", -1)
		l = strings.Replace(l, "math.Pow", "\\pow", -1)
		l = strings.Replace(l, "math.Exp", "\\exp", -1)
		l = strings.Replace(l, "math.Sin", "\\sin", -1)
		l = strings.Replace(l, "math.Cos", "\\cos", -1)

		// star
		l = strings.Replace(l, "*", " \\, ", -1)

		// colon-equal
		l = strings.Replace(l, ":=", "=", -1)

		// add to results
		io.Ff(&buf, "%s\n", l)
		return
	})

	// write file
	io.WriteFileVD("/tmp/gosl", fnkey+".tex", &buf)
}
Beispiel #8
0
func main() {

	// catch errors
	defer func() {
		if err := recover(); err != nil {
			io.PfRed("ERROR: %v\n", err)
		}
	}()

	// input data
	simfn, _ := io.ArgToFilename(0, "data/twoqua4", ".sim", true)
	exnwl := io.ArgToBool(1, false)
	stgidx := io.ArgToInt(2, 0)
	io.Pf("\n%s\n", io.ArgsTable(
		"simulation filename", "simfn", simfn,
		"extrapolate nwl", "exnwl", exnwl,
		"stage index", "stgidx", stgidx,
	))

	// start analysis process
	out.Start(simfn, stgidx, 0)

	// global variables
	ndim = out.Dom.Msh.Ndim
	verts = out.Dom.Msh.Verts
	cells = out.Dom.Msh.Cells
	nodes = out.Dom.Nodes
	elems = out.Dom.Elems
	dirout = out.Dom.Sim.DirOut
	fnkey = out.Dom.Sim.Key
	steady = out.Dom.Sim.Data.Steady

	// flags
	has_u := out.Dom.YandC["ux"]
	has_pl := out.Dom.YandC["pl"]
	has_pg := out.Dom.YandC["pg"]
	has_sig := out.Ipkeys["sx"]
	has_nwl := out.Ipkeys["nwlx"]
	has_p := has_pl || has_pg
	lbb := has_u && has_p
	if out.Dom.Sim.Data.NoLBB {
		lbb = false
	}

	// buffers
	pvd := make(map[string]*bytes.Buffer)
	geo := make(map[string]*bytes.Buffer)
	vtu := make(map[string]*bytes.Buffer)
	if _, ok := out.Dom.YandC["ux"]; ok {
		pvd["u"] = new(bytes.Buffer)
		geo["u"] = new(bytes.Buffer)
		vtu["u"] = new(bytes.Buffer)
	}
	for ykey, _ := range out.Dom.Dof2Tnum {
		if ykey == "ux" || ykey == "uy" || ykey == "uz" {
			continue
		}
		pvd[ykey] = new(bytes.Buffer)
		geo[ykey] = new(bytes.Buffer)
		vtu[ykey] = new(bytes.Buffer)
		label2keys[ykey] = []string{ykey}
	}
	if len(out.Ipkeys) > 0 {
		pvd["ips"] = new(bytes.Buffer)
		geo["ips"] = new(bytes.Buffer)
		vtu["ips"] = new(bytes.Buffer)
	}
	if exnwl {
		pvd["ex_nwl"] = new(bytes.Buffer)
		geo["ex_nwl"] = new(bytes.Buffer)
		vtu["ex_nwl"] = new(bytes.Buffer)
	}

	// extrapolated values keys
	extrap_keys := []string{"nwlx", "nwly"}
	if ndim == 3 {
		extrap_keys = []string{"nwlx", "nwly", "nwlz"}
	}

	// headers
	for _, b := range pvd {
		pvd_header(b)
	}

	// process results
	for tidx, t := range out.Sum.OutTimes {

		// input results into domain
		err := out.Dom.Read(out.Sum, tidx, 0, true)
		if err != nil {
			chk.Panic("cannot load results into domain\n%v", err)
		}

		// message
		io.PfWhite("time     = %g\r", t)

		// generate topology
		if tidx == 0 {
			for label, b := range geo {
				topology(b, label == "ips", lbb)
			}

			// allocate integration points values
			ipvals = make([]map[string]float64, len(out.Ipoints))
			for i, _ := range out.Ipoints {
				ipvals[i] = make(map[string]float64)
			}
		}

		// get integration points values @ time t
		for i, p := range out.Ipoints {
			vals := p.Calc(out.Dom.Sol)
			for key, val := range vals {
				ipvals[i][key] = val
			}
		}

		// compute extrapolated values
		if exnwl {
			out.ComputeExtrapolatedValues(extrap_keys)
		}

		// for each data buffer
		for label, b := range vtu {

			// reset buffer
			b.Reset()

			// points data
			if label == "ips" {
				pdata_open(b)
				if has_sig {
					pdata_write(b, "sig", skeys, true)
				}
				if has_nwl {
					pdata_write(b, "nwl", nwlkeys, true)
				}
				for key, _ := range out.Ipkeys {
					if !is_sig[key] && !is_nwl[key] {
						pdata_write(b, key, []string{key}, true)
					}
				}
				pdata_close(b)
			} else {
				pdata_open(b)
				pdata_write(b, label, label2keys[label], false)
				pdata_close(b)
			}

			// cells data
			cdata_write(b, label == "ips")

			// write vtu file
			vtu_write(geo[label], b, tidx, label)
		}

		// pvd
		for label, b := range pvd {
			pvd_line(b, tidx, t, label)
		}
	}

	// write pvd files
	for label, b := range pvd {
		pvd_write(b, label)
	}
}
Beispiel #9
0
// LogParams returns a log with current parameters
func (o *Parameters) LogParams() (l string) {

	// sizes
	l += io.ArgsTable("SIZES",
		"number of objective values", "Nova", o.Nova,
		"number of out-of-range values", "Noor", o.Noor,
		"total number of solutions", "Nsol", o.Nsol,
		"number of cpus", "Ncpu", o.Ncpu,
	)

	// time
	l += "\n"
	l += io.ArgsTable("TIME",
		"final time", "Tf", o.Tf,
		"delta time for exchange", "DtExc", o.DtExc,
		"delta time for output", "DtOut", o.DtOut,
	)

	// options
	l += "\n"
	l += io.ArgsTable("OPTIONS",
		"C-coefficient for differential evolution", "DEC", o.DEC,
		"parallel", "Pll", o.Pll,
		"seed for random numbers generator", "Seed", o.Seed,
		"generation type: 'latin', 'halton', 'rnd'", "GenType", o.GenType,
		"Latin Hypercube duplicates number", "LatinDup", o.LatinDup,
		"minimum value for 'h' constraints", "EpsH", o.EpsH,
		"show messages", "Verbose", o.Verbose,
		"show messages in Stat", "VerbStat", o.VerbStat,
		"show time messages", "VerbTime", o.VerbTime,
		"generate all solutions together", "GenAll", o.GenAll,
		"run many trials", "Nsamples", o.Nsamples,
		"integers represent binary numbers", "BinInt", o.BinInt,
		"clear flt if corresponding int is 0", "ClearFlt", o.ClearFlt,
		"use exchange via tournament", "ExcTour", o.ExcTour,
		"use exchange one randomly", "ExcOne", o.ExcOne,
		"normalise float values", "NormFlt", o.NormFlt,
		"use meshes to control points movement", "UseMesh", o.UseMesh,
		"number of points along boundary / per iFlt (only if UseMesh==true)", "Nbry", o.Nbry,
	)

	// crossover and mutation of integers
	l += "\n"
	l += io.ArgsTable("CROSSOVER AND MUTATION OF INTS",
		"probability of crossover for ints", "IntPc", o.IntPc,
		"number of cuts in crossover of ints", "IntNcuts", o.IntNcuts,
		"probability of mutation for ints", "IntPm", o.IntPm,
		"number of changes during mutation of ints", "IntNchanges", o.IntNchanges,
	)

	// derived
	l += "\n"
	l += io.ArgsTable("DERIVED",
		"number of floats", "Nflt", o.Nflt,
		"number of integers", "Nint", o.Nint,
		"number of (Xi,Xj) pairs", "NumXiXjPairs", o.NumXiXjPairs,
		"number of points along the boundaries of one (Xi,Xj) plane", "NumXiXjBryPts", o.NumXiXjBryPts,
		"total number of extra solutions due to all (Xi,Xj) boundaries", "NumExtraSols", o.NumExtraSols,
	)

	// extra
	l += "\n"
	l += io.ArgsTable("EXTRA",
		"strategy", "Strategy", o.Strategy,
		"plot set of graphs 1", "PlotSet1", o.PlotSet1,
		"plot set of graphs 2", "PlotSet2", o.PlotSet2,
		"problem number", "ProbNum", o.ProbNum,
	)
	return
}
Beispiel #10
0
func main() {

	// catch errors
	defer func() {
		if err := recover(); err != nil {
			io.PfRed("ERROR: %v\n", err)
		}
	}()

	// input data
	simfn, _ := io.ArgToFilename(0, "elast", ".sim", true)
	matname := io.ArgToString(1, "lrm1")
	pcmax := io.ArgToFloat(2, 30.0)
	npts := io.ArgToInt(3, 101)

	// print input table
	io.Pf("\n%s\n", io.ArgsTable(
		"simulation filename", "simfn", simfn,
		"material name", "matname", matname,
		"max pc", "pcmax", pcmax,
		"number of points", "npts", npts,
	))

	// load simulation
	sim := inp.ReadSim(simfn, "lrm", false, 0)
	if sim == nil {
		io.PfRed("cannot load simulation\n")
		return
	}

	// get material data
	mat := sim.MatParams.Get(matname)
	if mat == nil {
		io.PfRed("cannot get material\n")
		return
	}
	io.Pforan("mat = %v\n", mat)

	// get and initialise model
	mdl := mreten.GetModel(simfn, matname, mat.Model, false)
	if mdl == nil {
		io.PfRed("cannot allocate model\n")
		return
	}
	mdl.Init(mat.Prms)

	// plot drying path
	d_Pc := utl.LinSpace(0, pcmax, npts)
	d_Sl := make([]float64, npts)
	d_Sl[0] = 1
	var err error
	for i := 1; i < npts; i++ {
		d_Sl[i], err = mreten.Update(mdl, d_Pc[i-1], d_Sl[i-1], d_Pc[i]-d_Pc[i-1])
		if err != nil {
			io.PfRed("drying: cannot updated model\n%v\n", err)
			return
		}
	}
	plt.Plot(d_Pc, d_Sl, io.Sf("'b-', label='%s (dry)', clip_on=0", matname))

	// plot wetting path
	w_Pc := utl.LinSpace(pcmax, 0, npts)
	w_Sl := make([]float64, npts)
	w_Sl[0] = d_Sl[npts-1]
	for i := 1; i < npts; i++ {
		w_Sl[i], err = mreten.Update(mdl, w_Pc[i-1], w_Sl[i-1], w_Pc[i]-w_Pc[i-1])
		if err != nil {
			io.PfRed("wetting: cannot updated model\n%v\n", err)
			return
		}
	}
	plt.Plot(w_Pc, w_Sl, io.Sf("'c-', label='%s (wet)', clip_on=0", matname))

	// save results
	type Results struct{ Pc, Sl []float64 }
	res := Results{append(d_Pc, w_Pc...), append(d_Sl, w_Sl...)}
	var buf bytes.Buffer
	enc := json.NewEncoder(&buf)
	err = enc.Encode(&res)
	if err != nil {
		io.PfRed("cannot encode results\n")
		return
	}
	fn := path.Join(sim.Data.DirOut, matname+".dat")
	io.WriteFile(fn, &buf)
	io.Pf("file <%s> written\n", fn)

	// show figure
	plt.AxisYrange(0, 1)
	plt.Cross("")
	plt.Gll("$p_c$", "$s_{\\ell}$", "")
	plt.Show()
}
Beispiel #11
0
func main() {

	// catch errors
	defer func() {
		if err := recover(); err != nil {
			io.PfRed("ERROR: %v\n", err)
		}
	}()

	// input data
	matfn, fnk := io.ArgToFilename(0, "materials", ".mat", true)
	io.Pf("\n%s\n", io.ArgsTable(
		"material filename", "matfn", matfn,
	))

	// skip variables
	skip := "gref nowet α"

	// skip parameters
	skipp := make(map[string]bool)
	for _, key := range io.SplitKeys(skip) {
		skipp[key] = true
	}

	// Read
	mdb := inp.ReadMat("", matfn)

	// Get max number of parameters
	nmaxprms := 0
	for _, mdat := range mdb.Materials {
		n := len(mdat.Prms)
		if n > nmaxprms {
			nmaxprms = n
		}
	}

	// header
	b := new(bytes.Buffer)
	io.Ff(b, "\\documentclass[12pt,a4paper]{article}\n")
	io.Ff(b, "\\usepackage[margin=2.0cm,footskip=0.5cm]{geometry}\n")
	io.Ff(b, "\\usepackage[labelfont=bf,tableposition=top,aboveskip=4pt]{caption}\n")
	io.Ff(b, "\\usepackage{tabularx}\n")
	io.Ff(b, "\\usepackage{booktabs}\n")
	io.Ff(b, "\n")
	io.Ff(b, "\\title{Materials Table}\n")
	io.Ff(b, "\\author{GoFem MatTable tool}\n")
	io.Ff(b, "\n")
	io.Ff(b, "\\begin{document}\n")
	io.Ff(b, "\\maketitle\n")

	// table with parameters
	io.Ff(b, "\n")
	io.Ff(b, "\\begin{table} \\centering\n")
	io.Ff(b, "\\caption{Parameters from %s}\n", matfn)
	io.Ff(b, "\\begin{tabularx}{\\linewidth}[c]{l %s} \\toprule\n", strings.Repeat("c", nmaxprms))

	for i, mdat := range mdb.Materials {
		necols := nmaxprms - len(mdat.Prms) // number of empty cols

		// mat name
		io.Ff(b, "  %-20s", mdat.Name)

		// parameters names
		for _, param := range mdat.Prms {
			io.Ff(b, " &%12s", ToTex(param.N))
		}

		io.Ff(b, " %s", strings.Repeat(" &", necols))
		io.Ff(b, " \\\\\n")

		// values
		io.Ff(b, "  %-20s", "")
		for _, param := range mdat.Prms {
			io.Ff(b, " &%12s", NumFormat(param.V))
		}

		io.Ff(b, " %s", strings.Repeat(" &", necols))
		io.Ff(b, " \\\\\n")

		// units
		io.Ff(b, "  %-20s", "")
		for _, param := range mdat.Prms {
			if param.U == "" {
				io.Ff(b, " &%12v", "-")
			} else {
				io.Ff(b, " &%12v", UnitFormat(param.U))
			}
		}

		io.Ff(b, " %s", strings.Repeat(" &", necols))
		io.Ff(b, " \\\\\n")

		if i < len(mdb.Materials)-1 {
			io.Ff(b, "  \\\\\n")
		}
	}

	// footer
	io.Ff(b, "  \\bottomrule\n\\end{tabularx}\n\\label{tab:prms}\n\\end{table}\n")
	io.Ff(b, "\\end{document}\n")
	io.WriteFileV(fnk+".tex", b)

}
Beispiel #12
0
func main() {

	// catch errors
	defer func() {
		if err := recover(); err != nil {
			io.PfRed("ERROR: %v\n", err)
		}
	}()

	// input data
	simfnA, fnkA := io.ArgToFilename(0, "o2elastCO", ".sim", true)
	skip := io.ArgToInt(1, 0)
	simfnB, fnkB := io.ArgToFilename(2, "", ".sim", false)
	labelA := io.ArgToString(3, "")
	labelB := io.ArgToString(4, "")

	// print input data
	io.Pf("\n%s\n", io.ArgsTable(
		"simulation filename", "simfnA", simfnA,
		"number of initial increments to skip", "skip", skip,
		"simulation filename for comparison", "simfnB", simfnB,
		"label for histogram", "labelA", labelA,
		"label for histogram", "labelB", labelB,
	))

	// read residuals
	residA, fnkA := read_summary(simfnA)
	residB, fnkB := read_summary(simfnB)

	// residuals: it => residuals
	io.Pf("\nResiduals A\n")
	io.Pf("============\n")
	residA.Print("%10.2e")
	if simfnB != "" {
		io.Pf("\nResiduals B\n")
		io.Pf("============\n")
		residB.Print("%10.2e")
	}
	io.Pf("\n")

	// plot convergence curves
	plot_conv_curve(fnkA, skip, residA)
	if simfnB != "" {
		plot_conv_curve(fnkB, skip, residB)
	}

	// plot histogram
	io.Pf("\n")
	X := [][]float64{count_iters(residA)}
	labels := []string{fnkA}
	if labelA != "" {
		labels[0] = labelA
	}
	if simfnB != "" {
		X = append(X, count_iters(residB))
		labels = append(labels, fnkB)
		if labelB != "" {
			labels[1] = labelB
		}
	}
	plt.Reset()
	plt.SetForEps(0.75, 300)
	plt.Hist(X, labels, "")
	plt.Gll("number of iterations", "counts", "")
	plt.SaveD("/tmp", "gofem_residplot_"+fnkA+"_"+fnkB+"_hist.eps")
}