Interpolator1D::Interpolator1D(const Vector<double>& x, const Vector<double>& y, InterpolationType interp_type) : x_values(x), y_values(y), interpolation_type(interp_type) { // number of nodes unsigned int n = x_values.size(); // calculate the spline coefficients according to the type // of interpolation switch (interpolation_type) { case LINEAR: spline_coeffs = setupSplineLinear(x_values, y_values); break; case SPLINE_MONOTONE: spline_coeffs = setupSplineMonotoneSpline(x_values, y_values); break; default: throw "CurveInterpolator type not allowed"; } // set up flat extrapolation for tail values by default. extrap_values.resize(2); extrap_values(0) = y_values(0); extrap_values(1) = y_values(n - 1); }
/** Calculation of a derivate with order h. @param h: order of the derivative. @param x: coordinate to interpolate to. */ double Interpolator1D::operator()(unsigned int h, double x) const { // This will be the returned value. // Initialize it to zero. double y = 0.0; if (x < x_values(0)) { if (h == 0) y = extrap_values(0); else y = 0; } else if (x > x_values(x_values.size() - 1)) { if (h == 0) y = extrap_values(1); else y = 0; } else { // if it is within the bounds, interpolate with the polynomial. unsigned int index; if (x == x_values(0)) index = 0; else if (x == x_values.last_v()) index = x_values.size() - 2; else { const double* itx = lower_bound(x_values.begin(), x_values.end(), x); itx--; index = itx - x_values.begin(); } y = calcSplineValue(index, h, x); } return y; }
/** * Interpolates the spline value for the a given abscissas "x" */ double Interpolator1D::operator()(double x) const { // This will be the returned value. // Initialize it to zero. double y = 0.0; if (x < x_values(0)) y = extrap_values(0); else if (x == x_values(0)) y = y_values(0); else if (x > x_values(x_values.size() - 1)) y = extrap_values(1); else { // if it is within the bounds, interpolate with the polynomial. const double* itx = lower_bound(x_values.begin(), x_values.end(), x); itx--; const unsigned int index = itx - x_values.begin(); //Important note!: spline values could be different from //node values because of discontinuity of the spline at the nodes. //When the spline is discontinuous, the function value is one half //the value from the left and the value from the right. if (x == x_values(index)) y = y_values(index); else if (x == x_values(index + 1)) y = y_values(index + 1); else y = calcSplineValue(index, 0, x); } return y; }
// // extrapolate from integration points and compute output nodal/element // values // void FSDielectricElastomer2DT::ComputeOutput(const iArrayT& n_codes, dArray2DT& n_values, const iArrayT& e_codes, dArray2DT& e_values) { // // number of output values // int n_out = n_codes.Sum(); int e_out = e_codes.Sum(); // nothing to output if (n_out == 0 && e_out == 0) return; // dimensions int nsd = NumSD(); int ndof = NumDOF(); int nen = NumElementNodes(); int nnd = ElementSupport().NumNodes(); // reset averaging work space ElementSupport().ResetAverage(n_out); // allocate element results space e_values.Dimension(NumElements(), e_out); // nodal work arrays dArray2DT nodal_space(nen, n_out); dArray2DT nodal_all(nen, n_out); dArray2DT coords, disp; dArray2DT nodalstress, princstress, matdat; dArray2DT energy, speed; dArray2DT ndElectricScalarPotential; dArray2DT ndElectricDisplacement; dArray2DT ndElectricField; // ip values dArrayT ipmat(n_codes[iMaterialData]), ipenergy(1); dArrayT ipspeed(nsd), ipprincipal(nsd); dMatrixT ippvector(nsd); // set shallow copies double* pall = nodal_space.Pointer(); coords.Alias(nen, n_codes[iNodalCoord], pall); pall += coords.Length(); disp.Alias(nen, n_codes[iNodalDisp], pall); pall += disp.Length(); nodalstress.Alias(nen, n_codes[iNodalStress], pall); pall += nodalstress.Length(); princstress.Alias(nen, n_codes[iPrincipal], pall); pall += princstress.Length(); energy.Alias(nen, n_codes[iEnergyDensity], pall); pall += energy.Length(); speed.Alias(nen, n_codes[iWaveSpeeds], pall); pall += speed.Length(); matdat.Alias(nen, n_codes[iMaterialData], pall); pall += matdat.Length(); ndElectricDisplacement.Alias(nen, n_codes[ND_ELEC_DISP], pall); pall += ndElectricDisplacement.Length(); ndElectricField.Alias(nen, n_codes[ND_ELEC_FLD], pall); pall += ndElectricField.Length(); ndElectricScalarPotential.Alias(nen, n_codes[ND_ELEC_POT_SCALAR], pall); pall += ndElectricScalarPotential.Length(); // element work arrays dArrayT element_values(e_values.MinorDim()); pall = element_values.Pointer(); dArrayT centroid, ip_centroid, ip_mass; dArrayT ip_coords(nsd); if (e_codes[iCentroid]) { centroid.Alias(nsd, pall); pall += nsd; ip_centroid.Dimension(nsd); } if (e_codes[iMass]) { ip_mass.Alias(NumIP(), pall); pall += NumIP(); } double w_tmp, ke_tmp; double mass; double& strain_energy = (e_codes[iStrainEnergy]) ? *pall++ : w_tmp; double& kinetic_energy = (e_codes[iKineticEnergy]) ? *pall++ : ke_tmp; dArrayT linear_momentum, ip_velocity; if (e_codes[iLinearMomentum]) { linear_momentum.Alias(ndof, pall); pall += ndof; ip_velocity.Dimension(ndof); } else if (e_codes[iKineticEnergy]) ip_velocity.Dimension(ndof); dArray2DT ip_stress; if (e_codes[iIPStress]) { ip_stress.Alias(NumIP(), e_codes[iIPStress] / NumIP(), pall); pall += ip_stress.Length(); } dArray2DT ip_material_data; if (e_codes[iIPMaterialData]) { ip_material_data.Alias(NumIP(), e_codes[iIPMaterialData] / NumIP(), pall); pall += ip_material_data.Length(); ipmat.Dimension(ip_material_data.MinorDim()); } dArray2DT ipElectricDisplacement; if (e_codes[IP_ELEC_DISP]) { ipElectricDisplacement.Alias(NumIP(), NumSD(), pall); pall += NumIP() * NumSD(); } dArray2DT ipElectricField; if (e_codes[IP_ELEC_FLD]) { ipElectricField.Alias(NumIP(), NumSD(), pall); pall += NumIP() * NumSD(); } // check that degrees are displacements int interpolant_DOF = InterpolantDOFs(); Top(); while (NextElement()) { if (CurrentElement().Flag() == ElementCardT::kOFF) continue; // initialize nodal_space = 0.0; // global shape function values SetGlobalShape(); // collect nodal values if (e_codes[iKineticEnergy] || e_codes[iLinearMomentum]) { if (fLocVel.IsRegistered()) SetLocalU(fLocVel); else fLocVel = 0.0; } // coordinates and displacements all at once if (n_codes[iNodalCoord]) fLocInitCoords.ReturnTranspose(coords); if (n_codes[iNodalDisp]) { if (interpolant_DOF) fLocDisp.ReturnTranspose(disp); else NodalDOFs(CurrentElement().NodesX(), disp); } if (n_codes[ND_ELEC_POT_SCALAR]) { if (interpolant_DOF) { fLocScalarPotential.ReturnTranspose(ndElectricScalarPotential); } else { NodalDOFs(CurrentElement().NodesX(), ndElectricScalarPotential); } } // initialize element values mass = strain_energy = kinetic_energy = 0; if (e_codes[iCentroid]) centroid = 0.0; if (e_codes[iLinearMomentum]) linear_momentum = 0.0; const double* j = fShapes->IPDets(); const double* w = fShapes->IPWeights(); // integrate dArray2DT Na_X_ip_w; fShapes->TopIP(); while (fShapes->NextIP() != 0) { // density may change with integration point double density = fCurrMaterial->Density(); // element integration weight double ip_w = (*j++) * (*w++); if (qNoExtrap) { Na_X_ip_w.Dimension(nen, 1); for (int k = 0; k < nen; k++) { Na_X_ip_w(k, 0) = 1.; } } // get Cauchy stress const dSymMatrixT& stress = fCurrMaterial->s_ij(); dSymMatrixT strain; // stresses if (n_codes[iNodalStress]) { if (qNoExtrap) { for (int k = 0; k < nen; k++) { nodalstress.AddToRowScaled(k, Na_X_ip_w(k, 0), stress); } } else { fShapes->Extrapolate(stress, nodalstress); } } if (e_codes[iIPStress]) { double* row = ip_stress(fShapes->CurrIP()); strain.Set(nsd, row); strain = stress; row += stress.Length(); strain.Set(nsd, row); fCurrMaterial->Strain(strain); } // wave speeds if (n_codes[iWaveSpeeds]) { // acoustic wave speeds fCurrMaterial->WaveSpeeds(fNormal, ipspeed); if (qNoExtrap) { for (int k = 0; k < nen; k++) { speed.AddToRowScaled(k, Na_X_ip_w(k, 0), ipspeed); } } else { fShapes->Extrapolate(ipspeed, speed); } } // principal values - compute principal before smoothing if (n_codes[iPrincipal]) { // compute eigenvalues stress.PrincipalValues(ipprincipal); if (qNoExtrap) { for (int k = 0; k < nen; k++) { princstress.AddToRowScaled(k, Na_X_ip_w(k, 0), ipprincipal); } } else { fShapes->Extrapolate(ipprincipal, princstress); } } // strain energy density if (n_codes[iEnergyDensity] || e_codes[iStrainEnergy]) { double ip_strain_energy = fCurrMaterial->StrainEnergyDensity(); // nodal average if (n_codes[iEnergyDensity]) { ipenergy[0] = ip_strain_energy; if (qNoExtrap) { for (int k = 0; k < nen; k++) { energy.AddToRowScaled(k, Na_X_ip_w(k, 0), ipenergy); } } else { fShapes->Extrapolate(ipenergy, energy); } } // integrate over element if (e_codes[iStrainEnergy]) { strain_energy += ip_w * ip_strain_energy; } } // material stuff if (n_codes[iMaterialData] || e_codes[iIPMaterialData]) { // compute material output fCurrMaterial->ComputeOutput(ipmat); // store nodal data if (n_codes[iMaterialData]) { if (qNoExtrap) { for (int k = 0; k < nen; k++) { matdat.AddToRowScaled(k, Na_X_ip_w(k, 0), ipmat); } } else { fShapes->Extrapolate(ipmat, matdat); } } // store element data if (e_codes[iIPMaterialData]) { ip_material_data.SetRow(fShapes->CurrIP(), ipmat); } } // mass averaged centroid if (e_codes[iCentroid] || e_codes[iMass]) { // mass mass += ip_w * density; // integration point mass if (e_codes[iMass]) ip_mass[fShapes->CurrIP()] = ip_w * density; // moment if (e_codes[iCentroid]) { fShapes->IPCoords(ip_centroid); centroid.AddScaled(ip_w * density, ip_centroid); } } // kinetic energy/linear momentum if (e_codes[iKineticEnergy] || e_codes[iLinearMomentum]) { // velocity at integration point fShapes->InterpolateU(fLocVel, ip_velocity); double ke_density = 0.5 * density * dArrayT::Dot(ip_velocity, ip_velocity); // kinetic energy if (e_codes[iKineticEnergy]) { kinetic_energy += ip_w * ke_density; } // linear momentum if (e_codes[iLinearMomentum]) { linear_momentum.AddScaled(ip_w * density, ip_velocity); } } // electric displacements const dArrayT& D = fCurrMaterial->D_I(); if (n_codes[ND_ELEC_DISP]) { if (qNoExtrap) { for (int k = 0; k < nen; k++) { ndElectricDisplacement.AddToRowScaled(k, Na_X_ip_w(k, 0), D); } } else { fShapes->Extrapolate(D, ndElectricDisplacement); } } // electric field const dArrayT& E = fCurrMaterial->E_I(); if (n_codes[ND_ELEC_FLD]) { if (qNoExtrap) { for (int k = 0; k < nen; k++) { ndElectricField.AddToRowScaled(k, Na_X_ip_w(k, 0), E); } } else { fShapes->Extrapolate(E, ndElectricField); } } } // copy in the cols int colcount = 0; nodal_all.BlockColumnCopyAt(disp, colcount); colcount += disp.MinorDim(); nodal_all.BlockColumnCopyAt(coords, colcount); colcount += coords.MinorDim(); if (qNoExtrap) { double nip(fShapes->NumIP()); nodalstress /= nip; princstress /= nip; energy /= nip; speed /= nip; matdat /= nip; ndElectricDisplacement /= nip; ndElectricField /= nip; ndElectricScalarPotential /= nip; } nodal_all.BlockColumnCopyAt(nodalstress, colcount); colcount += nodalstress.MinorDim(); nodal_all.BlockColumnCopyAt(princstress, colcount); colcount += princstress.MinorDim(); nodal_all.BlockColumnCopyAt(energy, colcount); colcount += energy.MinorDim(); nodal_all.BlockColumnCopyAt(speed, colcount); colcount += speed.MinorDim(); nodal_all.BlockColumnCopyAt(matdat, colcount); colcount += matdat.MinorDim(); nodal_all.BlockColumnCopyAt(ndElectricDisplacement, colcount); colcount += ndElectricDisplacement.MinorDim(); nodal_all.BlockColumnCopyAt(ndElectricField, colcount); colcount += ndElectricField.MinorDim(); nodal_all.BlockColumnCopyAt(ndElectricScalarPotential, colcount); colcount += ndElectricScalarPotential.MinorDim(); // accumulate - extrapolation done from ip's to corners => X nodes ElementSupport().AssembleAverage(CurrentElement().NodesX(), nodal_all); // element values if (e_codes[iCentroid]) centroid /= mass; // store results e_values.SetRow(CurrElementNumber(), element_values); } // get nodally averaged values const OutputSetT& output_set = ElementSupport().OutputSet(fOutputID); const iArrayT& nodes_used = output_set.NodesUsed(); dArray2DT extrap_values(nodes_used.Length(), n_out); extrap_values.RowCollect(nodes_used, ElementSupport().OutputAverage()); int tmpDim = extrap_values.MajorDim(); n_values.Dimension(tmpDim, n_out); n_values.BlockColumnCopyAt(extrap_values, 0); }