| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | import FreeCAD |
| | import numpy as np |
| |
|
| |
|
| | class SegmentFunctionSegment: |
| | "One segment of a segment function" |
| |
|
| | def __init__(self, st, var, coeff, exp): |
| | self.start = st |
| | self.variable = var |
| | self.coefficient = coeff |
| | self.exponent = exp |
| |
|
| | def hasStart(self, xval): |
| | "Return true if the start of this segment is xval" |
| | |
| | return abs(self.start - xval) < 1e-9 |
| |
|
| | def isZero(self): |
| | |
| | return abs(self.coefficient) < 1e-5 |
| |
|
| | def value(self, xval): |
| | if xval < self.start: |
| | return 0 |
| | else: |
| | return self.coefficient * pow(xval - self.start, self.exponent) |
| |
|
| | def clone(self): |
| | return SegmentFunctionSegment(self.start, self.variable, self.coefficient, self.exponent) |
| |
|
| | def negate(self): |
| | self.coefficient *= -1 |
| | return self |
| |
|
| | def negated(self): |
| | return SegmentFunctionSegment( |
| | self.start, self.variable, self.coefficient * -1.0, self.exponent |
| | ) |
| |
|
| | def __mul__(self, value): |
| | return SegmentFunctionSegment( |
| | self.start, self.variable, self.coefficient * value, self.exponent |
| | ) |
| |
|
| | def integrate(self): |
| | self.exponent = self.exponent + 1 |
| | self.coefficient = self.coefficient * 1 / self.exponent |
| | return self |
| |
|
| | def asString(self): |
| | return "%f * {%s - %f}^%i" % (self.coefficient, self.variable, self.start, self.exponent) |
| |
|
| |
|
| | class SegmentFunction: |
| | "Function that is defined segment-wise" |
| |
|
| | def __init__(self, name="f(x)"): |
| | self.variable = "x" |
| | self.segments = [] |
| | self.name = name |
| |
|
| | def findSegment(self, xval): |
| | "Find segment valid for the given xval" |
| | for s in self.segments: |
| | if s.start <= xval: |
| | return s |
| | return self.segments[len(self.segments)] |
| |
|
| | def isZero(self): |
| | for s in self.segments: |
| | if not s.isZero(): |
| | return False |
| | return True |
| |
|
| | def negate(self): |
| | for s in self.segments: |
| | s.negate() |
| | return self |
| |
|
| | def negated(self): |
| | result = SegmentFunction() |
| | result.variable = self.variable |
| | for s in self.segments: |
| | result.segments.append(s.negated()) |
| | return result |
| |
|
| | def __mul__(self, value): |
| | result = SegmentFunction() |
| | result.variable = self.variable |
| | for s in self.segments: |
| | result.segments.append(s * value) |
| | return result |
| |
|
| | def index(self, xval): |
| | "Find insert position for start value xval" |
| | lastStart = 0.0 |
| | for i in range(len(self.segments)): |
| | newStart = self.segments[i].start |
| | if (xval >= lastStart) and (xval < newStart): |
| | return i |
| | lastStart = newStart |
| | return len(self.segments) |
| |
|
| | def buildFromDict(self, var, dict): |
| | self.variable = var |
| | for key in sorted(dict): |
| | |
| | self.segments.append(SegmentFunctionSegment(key, var, dict[key], 0)) |
| |
|
| | def addSegment(self, st, coeff, exp=0.0): |
| | if abs(coeff) > 1e-9: |
| | self.segments.insert( |
| | self.index(st), SegmentFunctionSegment(st, self.variable, coeff, exp) |
| | ) |
| |
|
| | def addSegments(self, dict): |
| | for key in sorted(dict): |
| | self.addSegment(key, dict[key]) |
| |
|
| | def setMaxX(self, mx): |
| | self.maxX = mx |
| |
|
| | def value(self, xval): |
| | "Return the value of the function at the specified x value" |
| | result = 0 |
| | for s in self.segments: |
| | result = result + s.value(xval) |
| | return result |
| |
|
| | def lowervalue(self, xval): |
| | "Return the value of the previous segment at the specified x value" |
| | result = 0 |
| | for s in self.segments: |
| | result = result + s.value(xval - 1e-8) |
| | return result |
| |
|
| | def clone(self): |
| | result = SegmentFunction() |
| | result.variable = self.variable |
| | for s in self.segments: |
| | result.segments.append(s.clone()) |
| | return result |
| |
|
| | def integrate(self): |
| | "Integrate all segments with respect to the variable" |
| | for s in self.segments: |
| | s.integrate() |
| | return self |
| |
|
| | def integrated(self): |
| | "Return a copy of self integrated with respect to the variable" |
| | result = self.clone() |
| | result.integrate() |
| | return result |
| |
|
| | def evaluate(self, maxX, pointsX): |
| | |
| | offset = (maxX - self.segments[0].start) / (pointsX - 1) |
| | xvals = set([self.segments[0].start + s * offset for s in range(pointsX)]) |
| | starts = set([self.segments[i].start for i in range(len(self.segments))]) |
| | xvals = xvals.union(starts) |
| | xresult = [] |
| | yresult = [] |
| | for xval in sorted(xvals): |
| | if xval in starts: |
| | |
| | xresult.append(xval) |
| | yresult.append(self.lowervalue(xval)) |
| | xresult.append(xval) |
| | yresult.append(self.value(xval)) |
| | return (xresult, yresult) |
| |
|
| | def output(self): |
| | FreeCAD.Console.PrintMessage(self.name + " = ") |
| | for i in range(len(self.segments)): |
| | FreeCAD.Console.PrintMessage(self.segments[i].asString()) |
| | if i < len(self.segments) - 1: |
| | FreeCAD.Console.PrintMessage(" + ") |
| | FreeCAD.Console.PrintMessage("\n") |
| |
|
| |
|
| | class IntervalFunction: |
| | "Function defined in intervals" |
| |
|
| | def __init__(self): |
| | self.intervals = [] |
| | self.values = [] |
| |
|
| | def addInterval(self, begin, length, value): |
| | self.intervals.append((begin, length)) |
| | self.values.append(value) |
| |
|
| | def value(self, xval): |
| | for i in range(len(self.intervals)): |
| | if xval >= self.intervals[i][0] and xval < self.intervals[i][0] + self.intervals[i][1]: |
| | return self.values[i] |
| | return self.values[len(self.values) - 1] |
| |
|
| | def lowervalue(self, xval): |
| | return self.value(xval - 1e-8) |
| |
|
| | def index(self, xval): |
| | lastStart = 0.0 |
| | for i in range(len(self.intervals)): |
| | newStart = self.intervals[i][0] |
| | if (xval >= lastStart) and (xval < newStart): |
| | return i - 1 |
| | lastStart = newStart |
| | return len(self.intervals) - 1 |
| |
|
| | def interval(self, xval): |
| | "Return interval (begin, length) for this xval" |
| | return self.intervals[self.index(xval)] |
| |
|
| | def begin(self, xval): |
| | return self.intervals[self.index(xval)][0] |
| |
|
| | def length(self, xval): |
| | return self.intervals[self.index(xval)][1] |
| |
|
| |
|
| | class StressFunction: |
| | "Specialization for segment-wise display of stresses" |
| |
|
| | |
| |
|
| | def __init__(self, f, i): |
| | self.segfunc = f |
| | self.intfunc = ( |
| | i |
| | ) |
| | name = "sigma" |
| |
|
| | def isZero(self): |
| | return self.segfunc.isZero() |
| |
|
| | def evaluate(self, maxX, pointsX): |
| | |
| | offset = (maxX - self.segfunc.segments[0].start) / (pointsX - 1) |
| | xvals = set([self.segfunc.segments[0].start + s * offset for s in range(pointsX)]) |
| | starts = set([self.segfunc.segments[i].start for i in range(len(self.segfunc.segments))]) |
| | xvals = xvals.union(starts) |
| | divs = set([self.intfunc.intervals[i][0] for i in range(len(self.intfunc.intervals))]) |
| | xvals = xvals.union(divs) |
| |
|
| | xresult = [] |
| | yresult = [] |
| | for xval in sorted(xvals): |
| | if xval in starts: |
| | |
| | xresult.append(xval) |
| | yresult.append(self.segfunc.lowervalue(xval) / self.intfunc.value(xval)) |
| | if xval in divs: |
| | |
| | xresult.append(xval) |
| | yresult.append(self.segfunc.value(xval) / self.intfunc.lowervalue(xval)) |
| | xresult.append(xval) |
| | yresult.append(self.segfunc.value(xval) / self.intfunc.value(xval)) |
| | return (xresult, yresult) |
| |
|
| |
|
| | class TranslationFunction: |
| | "Specialization for segment-wise display of translations" |
| |
|
| | def __init__(self, f, E, d, tangents, translations): |
| | if f.isZero(): |
| | self.transfunc = None |
| | return |
| | |
| | |
| | |
| | self.tangfunc = f.integrated() |
| | self.tangfunc.name = "w'" |
| | self.tangfunc.output() |
| | |
| | self.transfunc = ( |
| | self.tangfunc.integrated() |
| | ) |
| | self.transfunc.name = "w" |
| | self.transfunc.output() |
| | self.module = E |
| | self.intfunc = d |
| | self.name = "w" |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | A = np.zeros(shape=(2 * len(self.intfunc.intervals), 2 * len(self.intfunc.intervals))) |
| | |
| | b = np.zeros(shape=2 * len(self.intfunc.intervals)) |
| | |
| | row = 0 |
| |
|
| | |
| | for bound in tangents: |
| | xval = bound[0] |
| | tang = bound[1] |
| | i = self.intfunc.index(xval) |
| | I_i = self.intfunc.value(xval) |
| | |
| | A[row][2 * i] = 1.0 |
| | b[row] = tang * E * I_i - self.tangfunc.value(xval) |
| | row += 1 |
| | for bound in translations: |
| | xval = bound[0] |
| | trans = bound[1] |
| | i = self.intfunc.index(xval) |
| | I_i = self.intfunc.value(xval) |
| | |
| | A[row][2 * i] = xval / (E * I_i) |
| | A[row][2 * i + 1] = 1 / (E * I_i) |
| | b[row] = trans - self.transfunc.value(xval) / (E * I_i) |
| | row += 1 |
| |
|
| | |
| | for i in range(len(self.intfunc.intervals) - 1): |
| | x_start = self.intfunc.intervals[i][0] |
| | x_end = x_start + self.intfunc.intervals[i][1] |
| | I_i = self.intfunc.value(x_start) |
| | I_ip1 = self.intfunc.value(x_end) |
| | |
| | |
| | A[row][2 * i] = 1 / (E * I_i) |
| | A[row][2 * (i + 1)] = -1 / (E * I_ip1) |
| | b[row] = self.tangfunc.value(x_end) / (E * I_ip1) - self.tangfunc.value(x_end) / ( |
| | E * I_i |
| | ) |
| | row += 1 |
| | |
| | |
| | A[row][2 * i] = x_end / (E * I_i) |
| | A[row][2 * i + 1] = 1 / (E * I_i) |
| | A[row][2 * (i + 1)] = -x_end / (E * I_ip1) |
| | A[row][2 * (i + 1) + 1] = -1 / (E * I_ip1) |
| | b[row] = self.transfunc.value(x_end) / (E * I_ip1) - self.transfunc.value(x_end) / ( |
| | E * I_i |
| | ) |
| | row += 1 |
| |
|
| | |
| | |
| | |
| | |
| |
|
| | try: |
| | self.boundaries = np.linalg.solve(A, b) |
| | except np.linalg.linalg.LinAlgError as e: |
| | FreeCAD.Console.PrintMessage(e.message) |
| | FreeCAD.Console.PrintMessage(". No solution possible.\n") |
| | return |
| |
|
| | def isZero(self): |
| | if self.transfunc is None: |
| | return True |
| | return self.transfunc.isZero() |
| |
|
| | def evaluate(self, maxX, pointsX): |
| | |
| | offset = (maxX - self.transfunc.segments[0].start) / (pointsX - 1) |
| | xvals = set([self.transfunc.segments[0].start + s * offset for s in range(pointsX)]) |
| | starts = set( |
| | [self.transfunc.segments[i].start for i in range(len(self.transfunc.segments))] |
| | ) |
| | xvals = xvals.union(starts) |
| | divs = set([self.intfunc.intervals[i][0] for i in range(len(self.intfunc.intervals))]) |
| | xvals = xvals.union(divs) |
| | E = self.module |
| |
|
| | xresult = [] |
| | yresult = [] |
| | |
| | |
| | for xval in sorted(xvals): |
| | if xval in divs: |
| | i = self.intfunc.index(xval) |
| | (begin, length) = self.intfunc.interval(xval) |
| | I_i = self.intfunc.value(xval) |
| | C_i0 = self.boundaries[2 * i] |
| | C_i1 = self.boundaries[2 * i + 1] |
| | FreeCAD.Console.PrintMessage( |
| | "Interval %u: %f to %f, I_i: %f, C_i0: %f, C_i1: %f\n" |
| | % (i, begin, length, I_i, C_i0, C_i1) |
| | ) |
| |
|
| | xresult.append(xval) |
| | |
| | value = (self.transfunc.value(xval) + C_i0 * xval + C_i1) / (E * I_i) |
| | yresult.append(value) |
| |
|
| | return (xresult, yresult) |
| |
|