function bl = structuralBodyLoad(self,blInput)
%structuralBodyLoad - Apply body load to a structural model
% bl = structuralBodyLoad(structuralmodel,'Name',Value) applies body load
% to a structural model. Body load acts on the entire volume of the
% material.
%
% The name-value pairs for various types of structural body loads are:
%
% -------------------------------------------------------------------------
% Name			      	       Description
% -------------------------------------------------------------------------
% 'GravitationalAcceleration' Gravitational acceleration vector. Specify a 
%                             numeric vector representing the acceleration
%                             due to gravity in units consistent with the
%                             geometry and material properties of the
%                             model.
%
% 'AngularVelocity'           Angular velocity of a spinning axisymmetric
%                             structure. Specify a numeric scalar to model
%                             the centrifugal loading. The vertical axis is
%                             the default axis of rotation.
%
% 'Temperature'               Thermal load on a static structural analysis
%                             model. Specify a thermal load as a constant
%                             temperature or as a thermal analysis results
%                             object. Define the reference temperature that
%                             correspond to zero thermal-stress state as
%                             the ReferenceTemperature property of the
%                             structural model. Thermal gradients are
%                             assumed to be zero in case of constant
%                             temperature. The structuralBodyLoad function
%                             uses the temperature and its gradients from
%                             the steady-state thermal results object to
%                             evaluate thermal effects on the structure. In
%                             case of the transient thermal results object,
%                             structuralBodyLoad uses the temperature and
%                             its gradients from the last time step. To
%                             choose another time step, use the 'TimeStep'
%                             argument.
%
% 'TimeStep'                  Time index for the transient thermal results
%                             object. Use this argument in conjunction
%                             with 'Temperature' to specify the time-steps
%                             for the results to be used to evaluate
%                             thermal effects on the structure.
%
%'Label'                   Specify a customized label for linearizeInputs
%
%   Example 1: Specify gravity load on a beam.
% 
%       structuralmodel = createpde('structural','static-solid');
%       gm = importGeometry(structuralmodel,'SquareBeam.stl');
%       structuralProperties(structuralmodel,'YoungsModulus',210E9,...
%                                            'PoissonsRatio',0.3,...
%                                            'MassDensity',7800);
%       structuralBodyLoad(structuralmodel,'GravitationalAcceleration',...
%                                                             [0,0,-9.8]);
%
%   Example 2: Specify thermal load on a block for static analysis.
%
%       structuralmodel = createpde('structural','static-solid');
%       gm = importGeometry(structuralmodel,'BracketWithHole.stl');
%       structuralProperties(structuralmodel,'YoungsModulus',210E3, ...
%                                            'PoissonsRatio',0.3,...
%                                            'CTE',13.0E-6);
%       structuralBodyLoad(structuralmodel,'Temperature',100);
% 
% See also pde.StructuralModel, pde.StructuralModel/structuralProperties
%          pde.StructuralModel/structuralBoundaryLoad,
%          pde.StructuralModel/structuralBC, pde.StructuralModel/solve

% Copyright 2017-2023 The MathWorks, Inc.

arguments
    self pde.StructuralModel
    blInput.GravitationalAcceleration (1,:) {pde.internal.validators.mustBeDoubleVectorOrEmpty}
    blInput.AngularVelocity (1,:) {pde.internal.validators.mustBePositiveOrEmpty}
    blInput.Temperature  (1,:) {pde.internal.validators.mustBeTemperature}
    blInput.TimeStep (1,1) {mustBeNumeric, mustBePositive, mustBeInteger}
    blInput.Label {mustBeTextScalar, mustBeNonempty}
end

if isempty(self.Geometry)
    error(message('pde:StructuralModel:structuralModelHasNoGeom'));
end

if contains(self.AnalysisType,'modal')
    warning(message('pde:StructuralModel:bodyLoadsIgnoredInModal'))
end

if self.IsTwoD
    blInput.RegionType = 'Face';
    blInput.RegionID = 1:self.Geometry.NumFaces;
else
    blInput.RegionType = 'Cell';
    blInput.RegionID = 1:self.Geometry.NumCells;
end

if (contains(self.AnalysisType,{'modal','transient'}))
    if (isfield(blInput,'Temperature') && ~isempty(blInput.Temperature)) || ...
          (isfield(blInput,'TimeStep')  && ~isempty(blInput.TimeStep))
        error(message('pde:StructuralModel:thermalLoadingOnlyInStatic'));
    end
end

if isfield(blInput,'AngularVelocity') && ~isempty(blInput.AngularVelocity) ...
        && ~contains(self.AnalysisType,'axisymmetric')
    error(message('pde:StructuralModel:angularVelOnlyInAxisymm'))
end

if isempty(self.BodyLoads)
    self.BodyLoads = pde.BodyLoadAssignmentRecords(self);
   self.BodyLoads.BodyLoadAssignments = pde.BodyLoadAssignment.empty;
end

bl = pde.BodyLoadAssignment(self.BodyLoads,blInput);
self.BodyLoads.BodyLoadAssignments(end+1) = bl;
end